]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/build.py
BaseTools/Source/Python: New Target/ToolChain/Arch in DSC [BuildOptions]
[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
ab957f03 5# Copyright (c) 2007 - 2021, 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
5dc2699d 876 PcdMa.CreateAsBuiltInf()\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 891\r
ab957f03
MK
892 ## Add TOOLCHAIN and FAMILY declared in DSC [BuildOptions] to ToolsDefTxtDatabase.\r
893 #\r
894 # Loop through the set of build targets, tool chains, and archs provided on either\r
895 # the command line or in target.txt to discover FAMILY and TOOLCHAIN delclarations\r
896 # in [BuildOptions] sections that may be within !if expressions that may use\r
897 # $(TARGET), $(TOOLCHAIN), $(TOOLCHAIN_TAG), or $(ARCH) operands.\r
898 #\r
899 def GetToolChainAndFamilyFromDsc (self, File):\r
900 for BuildTarget in self.BuildTargetList:\r
901 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
902 for BuildToolChain in self.ToolChainList:\r
903 GlobalData.gGlobalDefines['TOOLCHAIN'] = BuildToolChain\r
904 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = BuildToolChain\r
905 for BuildArch in self.ArchList:\r
906 GlobalData.gGlobalDefines['ARCH'] = BuildArch\r
907 dscobj = self.BuildDatabase[File, BuildArch]\r
908 for KeyFamily, Key, KeyCodeBase in dscobj.BuildOptions:\r
909 try:\r
910 Target, ToolChain, Arch, Tool, Attr = Key.split('_')\r
911 except:\r
912 continue\r
913 if ToolChain == TAB_STAR or Attr != TAB_TOD_DEFINES_FAMILY:\r
914 continue\r
915 try:\r
916 Family = dscobj.BuildOptions[(KeyFamily, Key, KeyCodeBase)]\r
917 Family = Family.strip().strip('=').strip()\r
918 except:\r
919 continue\r
920 if TAB_TOD_DEFINES_FAMILY not in self.ToolDef.ToolsDefTxtDatabase:\r
921 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY] = {}\r
922 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]:\r
923 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][ToolChain] = Family\r
924 if TAB_TOD_DEFINES_BUILDRULEFAMILY not in self.ToolDef.ToolsDefTxtDatabase:\r
925 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY] = {}\r
926 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY]:\r
927 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][ToolChain] = Family\r
928 if TAB_TOD_DEFINES_TOOL_CHAIN_TAG not in self.ToolDef.ToolsDefTxtDatabase:\r
929 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] = []\r
930 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
931 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG].append(ToolChain)\r
932\r
52302d4d
LG
933 ## Load configuration\r
934 #\r
935 # This method will parse target.txt and get the build configurations.\r
936 #\r
937 def LoadConfiguration(self):\r
52302d4d
LG
938\r
939 # if no ARCH given in command line, get it from target.txt\r
0d2711a6 940 if not self.ArchList:\r
938cf4c3 941 self.ArchList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET_ARCH]\r
0d2711a6 942 self.ArchList = tuple(self.ArchList)\r
52302d4d
LG
943\r
944 # if no build target given in command line, get it from target.txt\r
0d2711a6 945 if not self.BuildTargetList:\r
938cf4c3 946 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET]\r
52302d4d
LG
947\r
948 # if no tool chain given in command line, get it from target.txt\r
0d2711a6 949 if not self.ToolChainList:\r
938cf4c3 950 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
4231a819 951 if self.ToolChainList is None or len(self.ToolChainList) == 0:\r
52302d4d
LG
952 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")\r
953\r
ab957f03
MK
954 if not self.PlatformFile:\r
955 PlatformFile = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
956 if not PlatformFile:\r
957 # Try to find one in current directory\r
958 WorkingDirectory = os.getcwd()\r
959 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
960 FileNum = len(FileList)\r
961 if FileNum >= 2:\r
962 EdkLogger.error("build", OPTION_MISSING,\r
963 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
964 elif FileNum == 1:\r
965 PlatformFile = FileList[0]\r
966 else:\r
967 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
968 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
969\r
970 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
971\r
972 self.GetToolChainAndFamilyFromDsc (self.PlatformFile)\r
973\r
52302d4d
LG
974 # check if the tool chains are defined or not\r
975 NewToolChainList = []\r
976 for ToolChain in self.ToolChainList:\r
977 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
978 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)\r
979 else:\r
980 NewToolChainList.append(ToolChain)\r
981 # if no tool chain available, break the build\r
982 if len(NewToolChainList) == 0:\r
983 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
984 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))\r
985 else:\r
986 self.ToolChainList = NewToolChainList\r
987\r
40b4e21d
YZ
988 ToolChainFamily = []\r
989 ToolDefinition = self.ToolDef.ToolsDefTxtDatabase\r
990 for Tool in self.ToolChainList:\r
991 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \\r
992 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:\r
688c7d21 993 EdkLogger.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool)\r
94c04559 994 ToolChainFamily.append(TAB_COMPILER_MSFT)\r
40b4e21d
YZ
995 else:\r
996 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])\r
997 self.ToolChainFamily = ToolChainFamily\r
998\r
1a624dd7 999 self.ThreadNumber = ThreadNum()\r
52302d4d
LG
1000 ## Initialize build configuration\r
1001 #\r
1002 # This method will parse DSC file and merge the configurations from\r
1003 # command line and target.txt, then get the final build configurations.\r
1004 #\r
1005 def InitBuild(self):\r
0d2711a6 1006 # parse target.txt, tools_def.txt, and platform file\r
4afd3d04 1007 self.LoadConfiguration()\r
0d2711a6
LG
1008\r
1009 # Allow case-insensitive for those from command line or configuration file\r
1010 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
52302d4d
LG
1011 if ErrorCode != 0:\r
1012 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1013\r
f0dc69e6
YZ
1014\r
1015 def InitPreBuild(self):\r
1016 self.LoadConfiguration()\r
d429fcd0
YZ
1017 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
1018 if ErrorCode != 0:\r
1019 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
f0dc69e6
YZ
1020 if self.BuildTargetList:\r
1021 GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]\r
1022 if self.ArchList:\r
1023 GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]\r
1024 if self.ToolChainList:\r
1025 GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]\r
1026 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]\r
40b4e21d
YZ
1027 if self.ToolChainFamily:\r
1028 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]\r
9eb87141 1029 if 'PREBUILD' in GlobalData.gCommandLineDefines:\r
f0dc69e6
YZ
1030 self.Prebuild = GlobalData.gCommandLineDefines.get('PREBUILD')\r
1031 else:\r
f0dc69e6 1032 self.Db_Flag = True\r
71cac3f7 1033 Platform = self.Db.MapPlatform(str(self.PlatformFile))\r
f0dc69e6
YZ
1034 self.Prebuild = str(Platform.Prebuild)\r
1035 if self.Prebuild:\r
af9c4e5e
MK
1036 PrebuildList = []\r
1037 #\r
1038 # Evaluate all arguments and convert arguments that are WORKSPACE\r
1039 # relative paths to absolute paths. Filter arguments that look like\r
1040 # flags or do not follow the file/dir naming rules to avoid false\r
1041 # positives on this conversion.\r
1042 #\r
1043 for Arg in self.Prebuild.split():\r
1044 #\r
1045 # Do not modify Arg if it looks like a flag or an absolute file path\r
1046 #\r
1047 if Arg.startswith('-') or os.path.isabs(Arg):\r
1048 PrebuildList.append(Arg)\r
1049 continue\r
1050 #\r
1051 # Do not modify Arg if it does not look like a Workspace relative\r
1052 # path that starts with a valid package directory name\r
1053 #\r
1054 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':\r
1055 PrebuildList.append(Arg)\r
1056 continue\r
1057 #\r
1058 # If Arg looks like a WORKSPACE relative path, then convert to an\r
1059 # absolute path and check to see if the file exists.\r
1060 #\r
1061 Temp = mws.join(self.WorkspaceDir, Arg)\r
1062 if os.path.isfile(Temp):\r
1063 Arg = Temp\r
1064 PrebuildList.append(Arg)\r
1065 self.Prebuild = ' '.join(PrebuildList)\r
1066 self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)\r
52302d4d 1067\r
f0dc69e6 1068 def InitPostBuild(self):\r
9eb87141 1069 if 'POSTBUILD' in GlobalData.gCommandLineDefines:\r
f0dc69e6
YZ
1070 self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')\r
1071 else:\r
71cac3f7 1072 Platform = self.Db.MapPlatform(str(self.PlatformFile))\r
f0dc69e6
YZ
1073 self.Postbuild = str(Platform.Postbuild)\r
1074 if self.Postbuild:\r
af9c4e5e
MK
1075 PostbuildList = []\r
1076 #\r
1077 # Evaluate all arguments and convert arguments that are WORKSPACE\r
1078 # relative paths to absolute paths. Filter arguments that look like\r
1079 # flags or do not follow the file/dir naming rules to avoid false\r
1080 # positives on this conversion.\r
1081 #\r
1082 for Arg in self.Postbuild.split():\r
1083 #\r
1084 # Do not modify Arg if it looks like a flag or an absolute file path\r
1085 #\r
1086 if Arg.startswith('-') or os.path.isabs(Arg):\r
1087 PostbuildList.append(Arg)\r
1088 continue\r
1089 #\r
1090 # Do not modify Arg if it does not look like a Workspace relative\r
1091 # path that starts with a valid package directory name\r
1092 #\r
1093 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':\r
1094 PostbuildList.append(Arg)\r
1095 continue\r
1096 #\r
1097 # If Arg looks like a WORKSPACE relative path, then convert to an\r
1098 # absolute path and check to see if the file exists.\r
1099 #\r
1100 Temp = mws.join(self.WorkspaceDir, Arg)\r
1101 if os.path.isfile(Temp):\r
1102 Arg = Temp\r
1103 PostbuildList.append(Arg)\r
1104 self.Postbuild = ' '.join(PostbuildList)\r
1105 self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)\r
1106\r
1107 def PassCommandOption(self, BuildTarget, TargetArch, ToolChain, PlatformFile, Target):\r
f0dc69e6
YZ
1108 BuildStr = ''\r
1109 if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):\r
1110 BuildStr += ' ' + ' '.join(GlobalData.gCommand)\r
1111 TargetFlag = False\r
1112 ArchFlag = False\r
1113 ToolChainFlag = False\r
af9c4e5e 1114 PlatformFileFlag = False\r
f0dc69e6
YZ
1115\r
1116 if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:\r
1117 TargetFlag = True\r
1118 if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:\r
1119 ArchFlag = True\r
1120 if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:\r
1121 ToolChainFlag = True\r
af9c4e5e
MK
1122 if GlobalData.gOptions and not GlobalData.gOptions.PlatformFile:\r
1123 PlatformFileFlag = True\r
f0dc69e6
YZ
1124\r
1125 if TargetFlag and BuildTarget:\r
1126 if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):\r
1127 BuildStr += ' -b ' + ' -b '.join(BuildTarget)\r
1128 elif isinstance(BuildTarget, str):\r
1129 BuildStr += ' -b ' + BuildTarget\r
1130 if ArchFlag and TargetArch:\r
1131 if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):\r
1132 BuildStr += ' -a ' + ' -a '.join(TargetArch)\r
1133 elif isinstance(TargetArch, str):\r
1134 BuildStr += ' -a ' + TargetArch\r
1135 if ToolChainFlag and ToolChain:\r
1136 if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):\r
1137 BuildStr += ' -t ' + ' -t '.join(ToolChain)\r
1138 elif isinstance(ToolChain, str):\r
1139 BuildStr += ' -t ' + ToolChain\r
af9c4e5e
MK
1140 if PlatformFileFlag and PlatformFile:\r
1141 if isinstance(PlatformFile, list) or isinstance(PlatformFile, tuple):\r
1142 BuildStr += ' -p ' + ' -p '.join(PlatformFile)\r
1143 elif isinstance(PlatformFile, str):\r
1144 BuildStr += ' -p' + PlatformFile\r
1145 BuildStr += ' --conf=' + GlobalData.gConfDirectory\r
1146 if Target:\r
1147 BuildStr += ' ' + Target\r
f0dc69e6
YZ
1148\r
1149 return BuildStr\r
1150\r
1151 def LaunchPrebuild(self):\r
1152 if self.Prebuild:\r
1153 EdkLogger.info("\n- Prebuild Start -\n")\r
1154 self.LaunchPrebuildFlag = True\r
134bbe88
YZ
1155 #\r
1156 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script\r
1157 # and preserve them for the rest of the main build step, because the child process environment will\r
1158 # evaporate as soon as it exits, we cannot get it in build step.\r
1159 #\r
ccaa7754 1160 PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory, '.cache', '.PrebuildEnv')\r
f0dc69e6
YZ
1161 if os.path.isfile(PrebuildEnvFile):\r
1162 os.remove(PrebuildEnvFile)\r
1163 if os.path.isfile(self.PlatformBuildPath):\r
1164 os.remove(self.PlatformBuildPath)\r
1165 if sys.platform == "win32":\r
1166 args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))\r
b926f2f2 1167 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6
YZ
1168 else:\r
1169 args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))\r
34816e7e 1170 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6
YZ
1171\r
1172 # launch two threads to read the STDOUT and STDERR\r
1173 EndOfProcedure = Event()\r
1174 EndOfProcedure.clear()\r
1175 if Process.stdout:\r
1176 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1177 StdOutThread.setName("STDOUT-Redirector")\r
1178 StdOutThread.setDaemon(False)\r
1179 StdOutThread.start()\r
1180\r
1181 if Process.stderr:\r
1182 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1183 StdErrThread.setName("STDERR-Redirector")\r
1184 StdErrThread.setDaemon(False)\r
1185 StdErrThread.start()\r
1186 # waiting for program exit\r
1187 Process.wait()\r
1188\r
1189 if Process.stdout:\r
1190 StdOutThread.join()\r
1191 if Process.stderr:\r
1192 StdErrThread.join()\r
1193 if Process.returncode != 0 :\r
1194 EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')\r
1195\r
1196 if os.path.exists(PrebuildEnvFile):\r
1197 f = open(PrebuildEnvFile)\r
1198 envs = f.readlines()\r
1199 f.close()\r
2f28dca1
ZF
1200 envs = [l.split("=", 1) for l in envs ]\r
1201 envs = [[I.strip() for I in item] for item in envs if len(item) == 2]\r
f0dc69e6
YZ
1202 os.environ.update(dict(envs))\r
1203 EdkLogger.info("\n- Prebuild Done -\n")\r
1204\r
91048b0d 1205 def LaunchPostbuild(self):\r
f0dc69e6
YZ
1206 if self.Postbuild:\r
1207 EdkLogger.info("\n- Postbuild Start -\n")\r
1208 if sys.platform == "win32":\r
b926f2f2 1209 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6 1210 else:\r
34816e7e 1211 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6
YZ
1212 # launch two threads to read the STDOUT and STDERR\r
1213 EndOfProcedure = Event()\r
1214 EndOfProcedure.clear()\r
1215 if Process.stdout:\r
1216 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1217 StdOutThread.setName("STDOUT-Redirector")\r
1218 StdOutThread.setDaemon(False)\r
1219 StdOutThread.start()\r
1220\r
1221 if Process.stderr:\r
1222 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1223 StdErrThread.setName("STDERR-Redirector")\r
1224 StdErrThread.setDaemon(False)\r
1225 StdErrThread.start()\r
1226 # waiting for program exit\r
1227 Process.wait()\r
1228\r
1229 if Process.stdout:\r
1230 StdOutThread.join()\r
1231 if Process.stderr:\r
1232 StdErrThread.join()\r
1233 if Process.returncode != 0 :\r
1234 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')\r
1235 EdkLogger.info("\n- Postbuild Done -\n")\r
0eccea3f 1236\r
52302d4d
LG
1237 ## Build a module or platform\r
1238 #\r
08dd311f 1239 # Create autogen code and makefile for a module or platform, and the launch\r
52302d4d
LG
1240 # "make" command to build it\r
1241 #\r
1242 # @param Target The target of build command\r
1243 # @param Platform The platform file\r
1244 # @param Module The module file\r
1245 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1246 # @param ToolChain The name of toolchain to build\r
1247 # @param Arch The arch of the module/platform\r
1248 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1249 # for dependent modules/Libraries\r
1250 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1251 # for dependent modules/Libraries\r
1252 #\r
673d09a2 1253 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand=None, PcdMaList=None):\r
4231a819 1254 if AutoGenObject is None:\r
52302d4d 1255 return False\r
673d09a2
FB
1256 if FfsCommand is None:\r
1257 FfsCommand = {}\r
52302d4d
LG
1258 # skip file generation for cleanxxx targets, run and fds target\r
1259 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1260 # for target which must generate AutoGen code and makefile\r
673d09a2
FB
1261 mqueue = mp.Queue()\r
1262 for m in AutoGenObject.GetAllModuleInfo:\r
1263 mqueue.put(m)\r
bfe36cb4 1264 mqueue.put((None,None,None,None,None,None,None))\r
0e7e7a26 1265 AutoGenObject.DataPipe.DataContainer = {"CommandTarget": self.Target}\r
373298ca
FB
1266 AutoGenObject.DataPipe.DataContainer = {"Workspace_timestamp": AutoGenObject.Workspace._SrcTimeStamp}\r
1267 AutoGenObject.CreateLibModuelDirs()\r
1268 AutoGenObject.DataPipe.DataContainer = {"LibraryBuildDirectoryList":AutoGenObject.LibraryBuildDirectoryList}\r
1269 AutoGenObject.DataPipe.DataContainer = {"ModuleBuildDirectoryList":AutoGenObject.ModuleBuildDirectoryList}\r
1270 AutoGenObject.DataPipe.DataContainer = {"FdsCommandDict": AutoGenObject.Workspace.GenFdsCommandDict}\r
673d09a2
FB
1271 self.Progress.Start("Generating makefile and code")\r
1272 data_pipe_file = os.path.join(AutoGenObject.BuildDir, "GlobalVar_%s_%s.bin" % (str(AutoGenObject.Guid),AutoGenObject.Arch))\r
1273 AutoGenObject.DataPipe.dump(data_pipe_file)\r
fc8b8dea
SS
1274 cqueue = mp.Queue()\r
1275 autogen_rt,errorcode = self.StartAutoGen(mqueue, AutoGenObject.DataPipe, self.SkipAutoGen, PcdMaList, cqueue)\r
373298ca
FB
1276 AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")\r
1277 with open(AutoGenIdFile,"w") as fw:\r
1278 fw.write("Arch=%s\n" % "|".join((AutoGenObject.Workspace.ArchList)))\r
1279 fw.write("BuildDir=%s\n" % AutoGenObject.Workspace.BuildDir)\r
1280 fw.write("PlatformGuid=%s\n" % str(AutoGenObject.Guid))\r
673d09a2
FB
1281 self.Progress.Stop("done!")\r
1282 if not autogen_rt:\r
1283 self.AutoGenMgr.TerminateWorkers()\r
373298ca 1284 self.AutoGenMgr.join(1)\r
673d09a2 1285 raise FatalError(errorcode)\r
52302d4d
LG
1286 AutoGenObject.CreateCodeFile(False)\r
1287 AutoGenObject.CreateMakeFile(False)\r
673d09a2
FB
1288 else:\r
1289 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1290 AutoGenObject.CreateCodeFile(True)\r
1291 AutoGenObject.CreateMakeFile(True)\r
52302d4d
LG
1292\r
1293 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1294 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1295\r
1296 BuildCommand = AutoGenObject.BuildCommand\r
4231a819 1297 if BuildCommand is None or len(BuildCommand) == 0:\r
0d2711a6
LG
1298 EdkLogger.error("build", OPTION_MISSING,\r
1299 "No build command found for this module. "\r
4afd3d04 1300 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
0d2711a6
LG
1301 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1302 ExtraData=str(AutoGenObject))\r
52302d4d 1303\r
03af2753
HC
1304 # run\r
1305 if Target == 'run':\r
03af2753
HC
1306 return True\r
1307\r
1308 # build modules\r
1309 if BuildModule:\r
1310 BuildCommand = BuildCommand + [Target]\r
1311 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
b8ac0b7f 1312 if GlobalData.gBinCacheDest:\r
fc8b8dea
SS
1313 self.GenDestCache()\r
1314 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
1315 # Only for --hash\r
1316 # Update PreMakeCacheChain files\r
1317 self.GenLocalPreMakeCache()\r
b8ac0b7f 1318 self.BuildModules = []\r
03af2753
HC
1319 return True\r
1320\r
1321 # build library\r
1322 if Target == 'libraries':\r
0c3e8e99
BF
1323 DirList = []\r
1324 for Lib in AutoGenObject.LibraryAutoGenList:\r
1325 if not Lib.IsBinaryModule:\r
1326 DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib))\r
1327 for Lib, LibAutoGen in DirList:\r
818283de 1328 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, self.MakeFileName)), 'pbuild']\r
0c3e8e99 1329 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen)\r
03af2753
HC
1330 return True\r
1331\r
1332 # build module\r
1333 if Target == 'modules':\r
0c3e8e99
BF
1334 DirList = []\r
1335 for Lib in AutoGenObject.LibraryAutoGenList:\r
1336 if not Lib.IsBinaryModule:\r
1337 DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib))\r
1338 for Lib, LibAutoGen in DirList:\r
818283de 1339 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, self.MakeFileName)), 'pbuild']\r
0c3e8e99
BF
1340 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen)\r
1341\r
1342 DirList = []\r
1343 for ModuleAutoGen in AutoGenObject.ModuleAutoGenList:\r
1344 if not ModuleAutoGen.IsBinaryModule:\r
1345 DirList.append((os.path.join(AutoGenObject.BuildDir, ModuleAutoGen.BuildDir),ModuleAutoGen))\r
1346 for Mod,ModAutoGen in DirList:\r
818283de 1347 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, self.MakeFileName)), 'pbuild']\r
0c3e8e99 1348 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,ModAutoGen)\r
a0a2cd1e 1349 self.CreateAsBuiltInf()\r
b8ac0b7f 1350 if GlobalData.gBinCacheDest:\r
fc8b8dea
SS
1351 self.GenDestCache()\r
1352 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
1353 # Only for --hash\r
1354 # Update PreMakeCacheChain files\r
1355 self.GenLocalPreMakeCache()\r
b8ac0b7f 1356 self.BuildModules = []\r
03af2753
HC
1357 return True\r
1358\r
1359 # cleanlib\r
1360 if Target == 'cleanlib':\r
1361 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
818283de 1362 LibMakefile = os.path.normpath(os.path.join(Lib, self.MakeFileName))\r
03af2753
HC
1363 if os.path.exists(LibMakefile):\r
1364 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1365 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1366 return True\r
1367\r
1368 # clean\r
1369 if Target == 'clean':\r
1370 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
818283de 1371 ModMakefile = os.path.normpath(os.path.join(Mod, self.MakeFileName))\r
03af2753
HC
1372 if os.path.exists(ModMakefile):\r
1373 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']\r
1374 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1375 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
818283de 1376 LibMakefile = os.path.normpath(os.path.join(Lib, self.MakeFileName))\r
03af2753
HC
1377 if os.path.exists(LibMakefile):\r
1378 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1379 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1380 return True\r
1381\r
1382 # cleanall\r
1383 if Target == 'cleanall':\r
1384 try:\r
1385 #os.rmdir(AutoGenObject.BuildDir)\r
1386 RemoveDirectory(AutoGenObject.BuildDir, True)\r
5b0671c1 1387 except WindowsError as X:\r
03af2753
HC
1388 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1389 return True\r
1390\r
1391 ## Build a module or platform\r
1392 #\r
1393 # Create autogen code and makefile for a module or platform, and the launch\r
1394 # "make" command to build it\r
1395 #\r
1396 # @param Target The target of build command\r
1397 # @param Platform The platform file\r
1398 # @param Module The module file\r
1399 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1400 # @param ToolChain The name of toolchain to build\r
1401 # @param Arch The arch of the module/platform\r
1402 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1403 # for dependent modules/Libraries\r
1404 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1405 # for dependent modules/Libraries\r
1406 #\r
1407 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
4231a819 1408 if AutoGenObject is None:\r
03af2753
HC
1409 return False\r
1410\r
1411 # skip file generation for cleanxxx targets, run and fds target\r
1412 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1413 # for target which must generate AutoGen code and makefile\r
1414 if not self.SkipAutoGen or Target == 'genc':\r
1415 self.Progress.Start("Generating code")\r
1416 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1417 self.Progress.Stop("done!")\r
1418 if Target == "genc":\r
1419 return True\r
1420\r
1421 if not self.SkipAutoGen or Target == 'genmake':\r
1422 self.Progress.Start("Generating makefile")\r
1423 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
1424 #AutoGenObject.CreateAsBuiltInf()\r
1425 self.Progress.Stop("done!")\r
1426 if Target == "genmake":\r
1427 return True\r
1428 else:\r
1429 # always recreate top/platform makefile when clean, just in case of inconsistency\r
673d09a2
FB
1430 AutoGenObject.CreateCodeFile(True)\r
1431 AutoGenObject.CreateMakeFile(True)\r
03af2753
HC
1432\r
1433 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1434 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1435\r
1436 BuildCommand = AutoGenObject.BuildCommand\r
4231a819 1437 if BuildCommand is None or len(BuildCommand) == 0:\r
03af2753
HC
1438 EdkLogger.error("build", OPTION_MISSING,\r
1439 "No build command found for this module. "\r
1440 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
1441 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1442 ExtraData=str(AutoGenObject))\r
1443\r
b0e23cf3
YL
1444 # build modules\r
1445 if BuildModule:\r
1446 if Target != 'fds':\r
1447 BuildCommand = BuildCommand + [Target]\r
1b8eca8b 1448 AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
b0e23cf3 1449 self.CreateAsBuiltInf()\r
b8ac0b7f 1450 if GlobalData.gBinCacheDest:\r
fc8b8dea
SS
1451 self.GenDestCache()\r
1452 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
1453 # Only for --hash\r
1454 # Update PreMakeCacheChain files\r
1455 self.GenLocalPreMakeCache()\r
b8ac0b7f 1456 self.BuildModules = []\r
b0e23cf3
YL
1457 return True\r
1458\r
03af2753
HC
1459 # genfds\r
1460 if Target == 'fds':\r
370544d1
DL
1461 if GenFdsApi(AutoGenObject.GenFdsCommandDict, self.Db):\r
1462 EdkLogger.error("build", COMMAND_FAILURE)\r
3a3a3af4
FZ
1463 Threshold = self.GetFreeSizeThreshold()\r
1464 if Threshold:\r
1465 self.CheckFreeSizeThreshold(Threshold, AutoGenObject.FvDir)\r
03af2753
HC
1466 return True\r
1467\r
1468 # run\r
1469 if Target == 'run':\r
03af2753
HC
1470 return True\r
1471\r
03af2753
HC
1472 # build library\r
1473 if Target == 'libraries':\r
1474 pass\r
1475\r
1476 # not build modules\r
1477\r
1478\r
1479 # cleanall\r
52302d4d
LG
1480 if Target == 'cleanall':\r
1481 try:\r
1482 #os.rmdir(AutoGenObject.BuildDir)\r
1483 RemoveDirectory(AutoGenObject.BuildDir, True)\r
5b0671c1 1484 except WindowsError as X:\r
52302d4d
LG
1485 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1486 return True\r
1487\r
6780eef1 1488 ## Rebase module image and Get function address for the input module list.\r
52302d4d
LG
1489 #\r
1490 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
1491 if ModeIsSmm:\r
1492 AddrIsOffset = False\r
98120f5f 1493 for InfFile in ModuleList:\r
da92f276
LG
1494 sys.stdout.write (".")\r
1495 sys.stdout.flush()\r
52302d4d
LG
1496 ModuleInfo = ModuleList[InfFile]\r
1497 ModuleName = ModuleInfo.BaseName\r
f3decdc3
LG
1498 ModuleOutputImage = ModuleInfo.Image.FileName\r
1499 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')\r
52302d4d
LG
1500 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1501 if not ModeIsSmm:\r
1502 BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
1503 #\r
1504 # Update Image to new BaseAddress by GenFw tool\r
1505 #\r
f3decdc3 1506 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
47fea6af 1507 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1508 else:\r
1509 #\r
1510 # Set new address to the section header only for SMM driver.\r
1511 #\r
f3decdc3 1512 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
47fea6af 1513 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d 1514 #\r
fb0b35e0 1515 # Collect function address from Map file\r
52302d4d 1516 #\r
f3decdc3 1517 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')\r
52302d4d
LG
1518 FunctionList = []\r
1519 if os.path.exists(ImageMapTable):\r
1520 OrigImageBaseAddress = 0\r
47fea6af 1521 ImageMap = open(ImageMapTable, 'r')\r
52302d4d
LG
1522 for LinStr in ImageMap:\r
1523 if len (LinStr.strip()) == 0:\r
1524 continue\r
1525 #\r
1526 # Get the preferred address set on link time.\r
1527 #\r
1528 if LinStr.find ('Preferred load address is') != -1:\r
1529 StrList = LinStr.split()\r
1530 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
1531\r
1532 StrList = LinStr.split()\r
1533 if len (StrList) > 4:\r
47fea6af 1534 if StrList[3] == 'f' or StrList[3] == 'F':\r
52302d4d
LG
1535 Name = StrList[1]\r
1536 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
1537 FunctionList.append ((Name, RelativeAddress))\r
39879ef2 1538\r
52302d4d
LG
1539 ImageMap.close()\r
1540 #\r
1541 # Add general information.\r
1542 #\r
1543 if ModeIsSmm:\r
d943b0c3 1544 MapBuffer.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
52302d4d 1545 elif AddrIsOffset:\r
d943b0c3 1546 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 1547 else:\r
d943b0c3 1548 MapBuffer.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
52302d4d
LG
1549 #\r
1550 # Add guid and general seciton section.\r
1551 #\r
1552 TextSectionAddress = 0\r
1553 DataSectionAddress = 0\r
1554 for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
1555 if SectionHeader[0] == '.text':\r
1556 TextSectionAddress = SectionHeader[1]\r
1557 elif SectionHeader[0] in ['.data', '.sdata']:\r
1558 DataSectionAddress = SectionHeader[1]\r
1559 if AddrIsOffset:\r
d943b0c3 1560 MapBuffer.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))\r
52302d4d 1561 else:\r
d943b0c3 1562 MapBuffer.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
f3decdc3
LG
1563 #\r
1564 # Add debug image full path.\r
1565 #\r
d943b0c3 1566 MapBuffer.append('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
52302d4d 1567 #\r
fb0b35e0 1568 # Add function address\r
52302d4d
LG
1569 #\r
1570 for Function in FunctionList:\r
1571 if AddrIsOffset:\r
d943b0c3 1572 MapBuffer.append(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
52302d4d 1573 else:\r
d943b0c3 1574 MapBuffer.append(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))\r
52302d4d
LG
1575 ImageMap.close()\r
1576\r
1577 #\r
1578 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1579 #\r
1580 if ModeIsSmm:\r
1581 BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
1582\r
1583 ## Collect MAP information of all FVs\r
1584 #\r
636f2be6 1585 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):\r
0d2711a6 1586 if self.Fdf:\r
52302d4d 1587 # First get the XIP base address for FV map file.\r
636f2be6 1588 GuidPattern = re.compile("[-a-fA-F0-9]+")\r
eebc135f 1589 GuidName = re.compile(r"\(GUID=[-a-fA-F0-9]+")\r
9eb87141 1590 for FvName in Wa.FdfProfile.FvDict:\r
52302d4d
LG
1591 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
1592 if not os.path.exists(FvMapBuffer):\r
1593 continue\r
1be2ed90 1594 FvMap = open(FvMapBuffer, 'r')\r
52302d4d
LG
1595 #skip FV size information\r
1596 FvMap.readline()\r
1597 FvMap.readline()\r
1598 FvMap.readline()\r
1599 FvMap.readline()\r
636f2be6
LG
1600 for Line in FvMap:\r
1601 MatchGuid = GuidPattern.match(Line)\r
4231a819 1602 if MatchGuid is not None:\r
636f2be6
LG
1603 #\r
1604 # Replace GUID with module name\r
1605 #\r
1606 GuidString = MatchGuid.group()\r
1607 if GuidString.upper() in ModuleList:\r
1608 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
d943b0c3 1609 MapBuffer.append(Line)\r
f3decdc3
LG
1610 #\r
1611 # Add the debug image full path.\r
1612 #\r
1613 MatchGuid = GuidName.match(Line)\r
4231a819 1614 if MatchGuid is not None:\r
f3decdc3
LG
1615 GuidString = MatchGuid.group().split("=")[1]\r
1616 if GuidString.upper() in ModuleList:\r
d943b0c3 1617 MapBuffer.append('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
f3decdc3 1618\r
52302d4d
LG
1619 FvMap.close()\r
1620\r
1621 ## Collect MAP information of all modules\r
1622 #\r
1623 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
da92f276
LG
1624 sys.stdout.write ("Generate Load Module At Fix Address Map")\r
1625 sys.stdout.flush()\r
52302d4d
LG
1626 PatchEfiImageList = []\r
1627 PeiModuleList = {}\r
1628 BtModuleList = {}\r
1629 RtModuleList = {}\r
1630 SmmModuleList = {}\r
1631 PeiSize = 0\r
1632 BtSize = 0\r
1633 RtSize = 0\r
1634 # reserve 4K size in SMRAM to make SMM module address not from 0.\r
1635 SmmSize = 0x1000\r
636f2be6
LG
1636 for ModuleGuid in ModuleList:\r
1637 Module = ModuleList[ModuleGuid]\r
52302d4d 1638 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
4afd3d04 1639\r
52302d4d
LG
1640 OutputImageFile = ''\r
1641 for ResultFile in Module.CodaTargetList:\r
1642 if str(ResultFile.Target).endswith('.efi'):\r
1643 #\r
1644 # module list for PEI, DXE, RUNTIME and SMM\r
1645 #\r
1646 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
1647 ImageClass = PeImageClass (OutputImageFile)\r
1648 if not ImageClass.IsValid:\r
1649 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
f3decdc3 1650 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)\r
0c60e60b 1651 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
1652 PeiModuleList[Module.MetaFile] = ImageInfo\r
1653 PeiSize += ImageInfo.Image.Size\r
0c60e60b 1654 elif Module.ModuleType in [EDK_COMPONENT_TYPE_BS_DRIVER, SUP_MODULE_DXE_DRIVER, SUP_MODULE_UEFI_DRIVER]:\r
52302d4d
LG
1655 BtModuleList[Module.MetaFile] = ImageInfo\r
1656 BtSize += ImageInfo.Image.Size\r
0c60e60b 1657 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 1658 RtModuleList[Module.MetaFile] = ImageInfo\r
52302d4d 1659 RtSize += ImageInfo.Image.Size\r
8bb63e37 1660 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
1661 SmmModuleList[Module.MetaFile] = ImageInfo\r
1662 SmmSize += ImageInfo.Image.Size\r
8bb63e37 1663 if Module.ModuleType == SUP_MODULE_DXE_SMM_DRIVER:\r
888d7f19 1664 PiSpecVersion = Module.Module.Specification.get('PI_SPECIFICATION_VERSION', '0x00000000')\r
52302d4d 1665 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
da92f276 1666 if int(PiSpecVersion, 16) < 0x0001000A:\r
52302d4d
LG
1667 BtModuleList[Module.MetaFile] = ImageInfo\r
1668 BtSize += ImageInfo.Image.Size\r
1669 break\r
1670 #\r
1671 # EFI image is final target.\r
1672 # Check EFI image contains patchable FixAddress related PCDs.\r
1673 #\r
1674 if OutputImageFile != '':\r
1675 ModuleIsPatch = False\r
1676 for Pcd in Module.ModulePcdList:\r
eece4292 1677 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:\r
52302d4d
LG
1678 ModuleIsPatch = True\r
1679 break\r
1680 if not ModuleIsPatch:\r
1681 for Pcd in Module.LibraryPcdList:\r
eece4292 1682 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:\r
52302d4d
LG
1683 ModuleIsPatch = True\r
1684 break\r
4afd3d04 1685\r
52302d4d
LG
1686 if not ModuleIsPatch:\r
1687 continue\r
1688 #\r
1689 # Module includes the patchable load fix address PCDs.\r
4afd3d04 1690 # It will be fixed up later.\r
52302d4d
LG
1691 #\r
1692 PatchEfiImageList.append (OutputImageFile)\r
4afd3d04 1693\r
52302d4d
LG
1694 #\r
1695 # Get Top Memory address\r
1696 #\r
1697 ReservedRuntimeMemorySize = 0\r
1698 TopMemoryAddress = 0\r
1699 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
1700 TopMemoryAddress = 0\r
1701 else:\r
1702 TopMemoryAddress = self.LoadFixAddress\r
1703 if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
1704 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
52302d4d
LG
1705\r
1706 #\r
1707 # Patch FixAddress related PCDs into EFI image\r
1708 #\r
4afd3d04 1709 for EfiImage in PatchEfiImageList:\r
52302d4d
LG
1710 EfiImageMap = EfiImage.replace('.efi', '.map')\r
1711 if not os.path.exists(EfiImageMap):\r
1712 continue\r
1713 #\r
1714 # Get PCD offset in EFI image by GenPatchPcdTable function\r
1715 #\r
4afd3d04 1716 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)\r
52302d4d
LG
1717 #\r
1718 # Patch real PCD value by PatchPcdValue tool\r
1719 #\r
1720 for PcdInfo in PcdTable:\r
1721 ReturnValue = 0\r
1722 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
b3e94a06 1723 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize // 0x1000))\r
52302d4d 1724 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
b3e94a06 1725 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize // 0x1000))\r
52302d4d 1726 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
b3e94a06 1727 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize // 0x1000))\r
52302d4d 1728 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
b3e94a06 1729 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize // 0x1000))\r
52302d4d
LG
1730 if ReturnValue != 0:\r
1731 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
4afd3d04 1732\r
d943b0c3
FB
1733 MapBuffer.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize // 0x1000))\r
1734 MapBuffer.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize // 0x1000))\r
1735 MapBuffer.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize // 0x1000))\r
52302d4d 1736 if len (SmmModuleList) > 0:\r
d943b0c3 1737 MapBuffer.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize // 0x1000))\r
4afd3d04
LG
1738\r
1739 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
52302d4d 1740 BtBaseAddr = TopMemoryAddress - RtSize\r
4afd3d04 1741 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize\r
52302d4d
LG
1742\r
1743 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
1744 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
1745 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
47fea6af 1746 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)\r
d943b0c3 1747 MapBuffer.append('\n\n')\r
da92f276
LG
1748 sys.stdout.write ("\n")\r
1749 sys.stdout.flush()\r
4afd3d04 1750\r
52302d4d
LG
1751 ## Save platform Map file\r
1752 #\r
1753 def _SaveMapFile (self, MapBuffer, Wa):\r
1754 #\r
1755 # Map file path is got.\r
1756 #\r
1757 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
1758 #\r
1759 # Save address map into MAP file.\r
1760 #\r
d943b0c3 1761 SaveFileOnChange(MapFilePath, ''.join(MapBuffer), False)\r
da92f276 1762 if self.LoadFixAddress != 0:\r
47fea6af 1763 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))\r
da92f276 1764 sys.stdout.flush()\r
52302d4d
LG
1765\r
1766 ## Build active platform for different build targets and different tool chains\r
1767 #\r
1768 def _BuildPlatform(self):\r
f0dc69e6 1769 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
52302d4d 1770 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1771 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1772 index = 0\r
52302d4d 1773 for ToolChain in self.ToolChainList:\r
0d2711a6
LG
1774 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1775 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1776 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1777 index += 1\r
52302d4d
LG
1778 Wa = WorkspaceAutoGen(\r
1779 self.WorkspaceDir,\r
0d2711a6 1780 self.PlatformFile,\r
52302d4d
LG
1781 BuildTarget,\r
1782 ToolChain,\r
1783 self.ArchList,\r
1784 self.BuildDatabase,\r
1785 self.TargetTxt,\r
1786 self.ToolDef,\r
1787 self.Fdf,\r
1788 self.FdList,\r
1789 self.FvList,\r
4234283c 1790 self.CapList,\r
f3decdc3 1791 self.SkuId,\r
9508d0fa
LG
1792 self.UniFlag,\r
1793 self.Progress\r
52302d4d 1794 )\r
0d2711a6
LG
1795 self.Fdf = Wa.FdfFile\r
1796 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
1797 self.BuildReport.AddPlatformReport(Wa)\r
1798 self.Progress.Stop("done!")\r
37de70b7
YZ
1799\r
1800 # Add ffs build to makefile\r
1801 CmdListDict = {}\r
1802 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
b1e27d17 1803 CmdListDict = self._GenFfsCmd(Wa.ArchList)\r
37de70b7 1804\r
03af2753 1805 for Arch in Wa.ArchList:\r
e8449e1d 1806 PcdMaList = []\r
03af2753
HC
1807 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1808 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
a0a2cd1e
FB
1809 for Module in Pa.Platform.Modules:\r
1810 # Get ModuleAutoGen object to generate C code file and makefile\r
e8449e1d 1811 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
4231a819 1812 if Ma is None:\r
a0a2cd1e 1813 continue\r
e8449e1d
FB
1814 if Ma.PcdIsDriver:\r
1815 Ma.PlatformInfo = Pa\r
673d09a2 1816 Ma.Workspace = Wa\r
e8449e1d 1817 PcdMaList.append(Ma)\r
a0a2cd1e 1818 self.BuildModules.append(Ma)\r
5f7bb391
FB
1819 Pa.DataPipe.DataContainer = {"FfsCommand":CmdListDict}\r
1820 Pa.DataPipe.DataContainer = {"Workspace_timestamp": Wa._SrcTimeStamp}\r
673d09a2 1821 self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict,PcdMaList=PcdMaList)\r
4afd3d04 1822\r
52302d4d 1823 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1824 if self.Target in ["", "all", "fds"]:\r
0d2711a6
LG
1825 for Arch in Wa.ArchList:\r
1826 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d
LG
1827 #\r
1828 # Check whether the set fix address is above 4G for 32bit image.\r
1829 #\r
1830 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
0d2711a6 1831 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
1832 #\r
1833 # Get Module List\r
1834 #\r
636f2be6 1835 ModuleList = {}\r
52302d4d
LG
1836 for Pa in Wa.AutoGenObjectList:\r
1837 for Ma in Pa.ModuleAutoGenList:\r
4231a819 1838 if Ma is None:\r
52302d4d
LG
1839 continue\r
1840 if not Ma.IsLibrary:\r
636f2be6 1841 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d 1842\r
d943b0c3 1843 MapBuffer = []\r
636f2be6
LG
1844 if self.LoadFixAddress != 0:\r
1845 #\r
1846 # Rebase module to the preferred memory address before GenFds\r
1847 #\r
1848 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
0d2711a6 1849 if self.Fdf:\r
b0e23cf3
YL
1850 #\r
1851 # create FDS again for the updated EFI image\r
1852 #\r
1853 self._Build("fds", Wa)\r
52302d4d
LG
1854 #\r
1855 # Create MAP file for all platform FVs after GenFds.\r
1856 #\r
636f2be6 1857 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1858 #\r
1859 # Save MAP buffer into MAP file.\r
1860 #\r
1861 self._SaveMapFile (MapBuffer, Wa)\r
373298ca 1862 self.CreateGuidedSectionToolsFile(Wa)\r
52302d4d
LG
1863\r
1864 ## Build active module for different build targets, different tool chains and different archs\r
1865 #\r
1866 def _BuildModule(self):\r
1867 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1868 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1869 index = 0\r
52302d4d 1870 for ToolChain in self.ToolChainList:\r
1b8eca8b 1871 WorkspaceAutoGenTime = time.time()\r
0d2711a6 1872 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 1873 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1874 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1875 index += 1\r
52302d4d
LG
1876 #\r
1877 # module build needs platform build information, so get platform\r
1878 # AutoGen first\r
1879 #\r
1880 Wa = WorkspaceAutoGen(\r
1881 self.WorkspaceDir,\r
0d2711a6 1882 self.PlatformFile,\r
52302d4d
LG
1883 BuildTarget,\r
1884 ToolChain,\r
1885 self.ArchList,\r
1886 self.BuildDatabase,\r
1887 self.TargetTxt,\r
1888 self.ToolDef,\r
1889 self.Fdf,\r
1890 self.FdList,\r
1891 self.FvList,\r
4234283c 1892 self.CapList,\r
f3decdc3 1893 self.SkuId,\r
9508d0fa
LG
1894 self.UniFlag,\r
1895 self.Progress,\r
1896 self.ModuleFile\r
52302d4d 1897 )\r
0d2711a6
LG
1898 self.Fdf = Wa.FdfFile\r
1899 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d 1900 Wa.CreateMakeFile(False)\r
37de70b7
YZ
1901 # Add ffs build to makefile\r
1902 CmdListDict = None\r
1903 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
b1e27d17 1904 CmdListDict = self._GenFfsCmd(Wa.ArchList)\r
0e7e7a26 1905\r
0e7e7a26
SS
1906 GlobalData.file_lock = mp.Lock()\r
1907 GlobalData.FfsCmd = CmdListDict\r
1908\r
52302d4d
LG
1909 self.Progress.Stop("done!")\r
1910 MaList = []\r
1b8eca8b
YZ
1911 ExitFlag = threading.Event()\r
1912 ExitFlag.clear()\r
1913 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
0d2711a6 1914 for Arch in Wa.ArchList:\r
1b8eca8b 1915 AutoGenStart = time.time()\r
0d2711a6 1916 GlobalData.gGlobalDefines['ARCH'] = Arch\r
16bad1fb
YZ
1917 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1918 for Module in Pa.Platform.Modules:\r
fbe53845 1919 if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name:\r
e8449e1d 1920 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
db4d47fd
CR
1921 if Ma is None:\r
1922 continue\r
b67735a7
FZ
1923 if Ma.PcdIsDriver:\r
1924 Ma.PlatformInfo = Pa\r
1925 Ma.Workspace = Wa\r
19bf8314 1926 MaList.append(Ma)\r
0e7e7a26 1927\r
fc8b8dea
SS
1928 if GlobalData.gUseHashCache and not GlobalData.gBinCacheDest and self.Target in [None, "", "all"]:\r
1929 if Ma.CanSkipbyPreMakeCache():\r
373298ca 1930 continue\r
fc8b8dea
SS
1931 else:\r
1932 self.PreMakeCacheMiss.add(Ma)\r
0e7e7a26 1933\r
119d8c42
YZ
1934 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1935 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1936 # for target which must generate AutoGen code and makefile\r
1937 if not self.SkipAutoGen or self.Target == 'genc':\r
cd498216 1938 self.Progress.Start("Generating code")\r
119d8c42 1939 Ma.CreateCodeFile(True)\r
cd498216
YZ
1940 self.Progress.Stop("done!")\r
1941 if self.Target == "genc":\r
1942 return True\r
119d8c42 1943 if not self.SkipAutoGen or self.Target == 'genmake':\r
cd498216 1944 self.Progress.Start("Generating makefile")\r
e3c8311f
FB
1945 if CmdListDict and self.Fdf and (Module.Path, Arch) in CmdListDict:\r
1946 Ma.CreateMakeFile(True, CmdListDict[Module.Path, Arch])\r
1947 del CmdListDict[Module.Path, Arch]\r
37de70b7
YZ
1948 else:\r
1949 Ma.CreateMakeFile(True)\r
cd498216
YZ
1950 self.Progress.Stop("done!")\r
1951 if self.Target == "genmake":\r
1952 return True\r
0e7e7a26
SS
1953\r
1954 if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:\r
fc8b8dea 1955 if Ma.CanSkipbyMakeCache():\r
0e7e7a26
SS
1956 continue\r
1957 else:\r
fc8b8dea 1958 self.MakeCacheMiss.add(Ma)\r
0e7e7a26 1959\r
16bad1fb 1960 self.BuildModules.append(Ma)\r
1b8eca8b
YZ
1961 self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
1962 MakeStart = time.time()\r
1963 for Ma in self.BuildModules:\r
1964 if not Ma.IsBinaryModule:\r
673d09a2 1965 Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))\r
1b8eca8b
YZ
1966 # Break build if any build thread has error\r
1967 if BuildTask.HasError():\r
1968 # we need a full version of makefile for platform\r
1969 ExitFlag.set()\r
1970 BuildTask.WaitForComplete()\r
1971 Pa.CreateMakeFile(False)\r
1972 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1973 # Start task scheduler\r
1974 if not BuildTask.IsOnGoing():\r
1975 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1976\r
1977 # in case there's an interruption. we need a full version of makefile for platform\r
1978 Pa.CreateMakeFile(False)\r
1979 if BuildTask.HasError():\r
1980 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1981 self.MakeTime += int(round((time.time() - MakeStart)))\r
1982\r
1983 MakeContiue = time.time()\r
1984 ExitFlag.set()\r
1985 BuildTask.WaitForComplete()\r
1986 self.CreateAsBuiltInf()\r
b8ac0b7f 1987 if GlobalData.gBinCacheDest:\r
fc8b8dea
SS
1988 self.GenDestCache()\r
1989 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
1990 # Only for --hash\r
1991 # Update PreMakeCacheChain files\r
1992 self.GenLocalPreMakeCache()\r
b8ac0b7f 1993 self.BuildModules = []\r
1b8eca8b
YZ
1994 self.MakeTime += int(round((time.time() - MakeContiue)))\r
1995 if BuildTask.HasError():\r
1996 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
d5d56f1b
LG
1997\r
1998 self.BuildReport.AddPlatformReport(Wa, MaList)\r
52302d4d
LG
1999 if MaList == []:\r
2000 EdkLogger.error(\r
2001 'build',\r
2002 BUILD_ERROR,\r
2003 "Module for [%s] is not a component of active platform."\\r
2004 " Please make sure that the ARCH and inf file path are"\\r
47fea6af 2005 " given in the same as in [%s]" % \\r
0d2711a6 2006 (', '.join(Wa.ArchList), self.PlatformFile),\r
52302d4d
LG
2007 ExtraData=self.ModuleFile\r
2008 )\r
2009 # Create MAP file when Load Fix Address is enabled.\r
0d2711a6
LG
2010 if self.Target == "fds" and self.Fdf:\r
2011 for Arch in Wa.ArchList:\r
52302d4d
LG
2012 #\r
2013 # Check whether the set fix address is above 4G for 32bit image.\r
2014 #\r
2015 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
2016 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
2017 #\r
2018 # Get Module List\r
2019 #\r
636f2be6 2020 ModuleList = {}\r
52302d4d
LG
2021 for Pa in Wa.AutoGenObjectList:\r
2022 for Ma in Pa.ModuleAutoGenList:\r
4231a819 2023 if Ma is None:\r
52302d4d
LG
2024 continue\r
2025 if not Ma.IsLibrary:\r
636f2be6 2026 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d 2027\r
d943b0c3 2028 MapBuffer = []\r
636f2be6
LG
2029 if self.LoadFixAddress != 0:\r
2030 #\r
2031 # Rebase module to the preferred memory address before GenFds\r
2032 #\r
2033 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
b0e23cf3
YL
2034 #\r
2035 # create FDS again for the updated EFI image\r
2036 #\r
1b8eca8b 2037 GenFdsStart = time.time()\r
b0e23cf3 2038 self._Build("fds", Wa)\r
1b8eca8b 2039 self.GenFdsTime += int(round((time.time() - GenFdsStart)))\r
52302d4d
LG
2040 #\r
2041 # Create MAP file for all platform FVs after GenFds.\r
2042 #\r
636f2be6 2043 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
2044 #\r
2045 # Save MAP buffer into MAP file.\r
2046 #\r
2047 self._SaveMapFile (MapBuffer, Wa)\r
2048\r
b1e27d17 2049 def _GenFfsCmd(self,ArchList):\r
f7496d71 2050 # convert dictionary of Cmd:(Inf,Arch)\r
9eb87141
CJ
2051 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...\r
2052 CmdSetDict = defaultdict(set)\r
b1e27d17 2053 GenFfsDict = GenFds.GenFfsMakefile('', GlobalData.gFdfParser, self, ArchList, GlobalData)\r
37de70b7
YZ
2054 for Cmd in GenFfsDict:\r
2055 tmpInf, tmpArch = GenFfsDict[Cmd]\r
9eb87141
CJ
2056 CmdSetDict[tmpInf, tmpArch].add(Cmd)\r
2057 return CmdSetDict\r
373298ca
FB
2058 def VerifyAutoGenFiles(self):\r
2059 AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")\r
2060 try:\r
2061 with open(AutoGenIdFile) as fd:\r
2062 lines = fd.readlines()\r
2063 except:\r
2064 return None\r
2065 for line in lines:\r
2066 if "Arch" in line:\r
2067 ArchList = line.strip().split("=")[1].split("|")\r
2068 if "BuildDir" in line:\r
2069 BuildDir = line.split("=")[1].strip()\r
2070 if "PlatformGuid" in line:\r
2071 PlatformGuid = line.split("=")[1].strip()\r
2072 GlobalVarList = []\r
2073 for arch in ArchList:\r
2074 global_var = os.path.join(BuildDir, "GlobalVar_%s_%s.bin" % (str(PlatformGuid),arch))\r
2075 if not os.path.exists(global_var):\r
2076 return None\r
2077 GlobalVarList.append(global_var)\r
2078 for global_var in GlobalVarList:\r
2079 data_pipe = MemoryDataPipe()\r
2080 data_pipe.load(global_var)\r
2081 target = data_pipe.Get("P_Info").get("Target")\r
2082 toolchain = data_pipe.Get("P_Info").get("ToolChain")\r
2083 archlist = data_pipe.Get("P_Info").get("ArchList")\r
2084 Arch = data_pipe.Get("P_Info").get("Arch")\r
2085 active_p = data_pipe.Get("P_Info").get("ActivePlatform")\r
2086 workspacedir = data_pipe.Get("P_Info").get("WorkspaceDir")\r
2087 PackagesPath = os.getenv("PACKAGES_PATH")\r
2088 mws.setWs(workspacedir, PackagesPath)\r
2089 LibraryBuildDirectoryList = data_pipe.Get("LibraryBuildDirectoryList")\r
2090 ModuleBuildDirectoryList = data_pipe.Get("ModuleBuildDirectoryList")\r
2091\r
2092 for m_build_dir in LibraryBuildDirectoryList:\r
818283de 2093 if not os.path.exists(os.path.join(m_build_dir,self.MakeFileName)):\r
373298ca
FB
2094 return None\r
2095 for m_build_dir in ModuleBuildDirectoryList:\r
818283de 2096 if not os.path.exists(os.path.join(m_build_dir,self.MakeFileName)):\r
373298ca
FB
2097 return None\r
2098 Wa = WorkSpaceInfo(\r
2099 workspacedir,active_p,target,toolchain,archlist\r
2100 )\r
2101 Pa = PlatformInfo(Wa, active_p, target, toolchain, Arch,data_pipe)\r
2102 Wa.AutoGenObjectList.append(Pa)\r
2103 return Wa\r
2104 def SetupMakeSetting(self,Wa):\r
2105 BuildModules = []\r
2106 for Pa in Wa.AutoGenObjectList:\r
2107 for m in Pa._MbList:\r
2108 ma = ModuleAutoGen(Wa,m.MetaFile, Pa.BuildTarget, Wa.ToolChain, Pa.Arch, Pa.MetaFile,Pa.DataPipe)\r
2109 BuildModules.append(ma)\r
2110 fdf_file = Wa.FlashDefinition\r
2111 if fdf_file:\r
2112 Fdf = FdfParser(fdf_file.Path)\r
2113 Fdf.ParseFile()\r
2114 GlobalData.gFdfParser = Fdf\r
2115 if Fdf.CurrentFdName and Fdf.CurrentFdName in Fdf.Profile.FdDict:\r
2116 FdDict = Fdf.Profile.FdDict[Fdf.CurrentFdName]\r
2117 for FdRegion in FdDict.RegionList:\r
49fb9f7e 2118 if str(FdRegion.RegionType) == 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList):\r
373298ca
FB
2119 if int(FdRegion.Offset) % 8 != 0:\r
2120 EdkLogger.error("build", FORMAT_INVALID, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion.Offset))\r
2121 Wa.FdfProfile = Fdf.Profile\r
2122 self.Fdf = Fdf\r
2123 else:\r
2124 self.Fdf = None\r
2125 return BuildModules\r
37de70b7 2126\r
52302d4d
LG
2127 ## Build a platform in multi-thread mode\r
2128 #\r
373298ca
FB
2129 def PerformAutoGen(self,BuildTarget,ToolChain):\r
2130 WorkspaceAutoGenTime = time.time()\r
2131 Wa = WorkspaceAutoGen(\r
2132 self.WorkspaceDir,\r
2133 self.PlatformFile,\r
2134 BuildTarget,\r
2135 ToolChain,\r
2136 self.ArchList,\r
2137 self.BuildDatabase,\r
2138 self.TargetTxt,\r
2139 self.ToolDef,\r
2140 self.Fdf,\r
2141 self.FdList,\r
2142 self.FvList,\r
2143 self.CapList,\r
2144 self.SkuId,\r
2145 self.UniFlag,\r
2146 self.Progress\r
2147 )\r
2148 self.Fdf = Wa.FdfFile\r
2149 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
2150 self.BuildReport.AddPlatformReport(Wa)\r
2151 Wa.CreateMakeFile(False)\r
2152\r
fc8b8dea 2153 # Add ffs build to makefile\r
373298ca
FB
2154 CmdListDict = {}\r
2155 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
2156 CmdListDict = self._GenFfsCmd(Wa.ArchList)\r
2157\r
373298ca
FB
2158 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
2159 BuildModules = []\r
373298ca
FB
2160 for Arch in Wa.ArchList:\r
2161 PcdMaList = []\r
2162 AutoGenStart = time.time()\r
2163 GlobalData.gGlobalDefines['ARCH'] = Arch\r
2164 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
2165 if Pa is None:\r
2166 continue\r
2167 ModuleList = []\r
2168 for Inf in Pa.Platform.Modules:\r
2169 ModuleList.append(Inf)\r
fc8b8dea 2170 # Add the INF only list in FDF\r
373298ca
FB
2171 if GlobalData.gFdfParser is not None:\r
2172 for InfName in GlobalData.gFdfParser.Profile.InfList:\r
2173 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)\r
2174 if Inf in Pa.Platform.Modules:\r
2175 continue\r
2176 ModuleList.append(Inf)\r
2177 Pa.DataPipe.DataContainer = {"FfsCommand":CmdListDict}\r
2178 Pa.DataPipe.DataContainer = {"Workspace_timestamp": Wa._SrcTimeStamp}\r
2179 Pa.DataPipe.DataContainer = {"CommandTarget": self.Target}\r
2180 Pa.CreateLibModuelDirs()\r
818283de
PG
2181 # Fetch the MakeFileName.\r
2182 self.MakeFileName = Pa.MakeFileName\r
2183 if not self.MakeFileName:\r
2184 self.MakeFileName = Pa.MakeFile\r
2185\r
373298ca
FB
2186 Pa.DataPipe.DataContainer = {"LibraryBuildDirectoryList":Pa.LibraryBuildDirectoryList}\r
2187 Pa.DataPipe.DataContainer = {"ModuleBuildDirectoryList":Pa.ModuleBuildDirectoryList}\r
2188 Pa.DataPipe.DataContainer = {"FdsCommandDict": Wa.GenFdsCommandDict}\r
fc8b8dea
SS
2189 # Prepare the cache share data for multiprocessing\r
2190 Pa.DataPipe.DataContainer = {"gPlatformHashFile":GlobalData.gPlatformHashFile}\r
373298ca
FB
2191 ModuleCodaFile = {}\r
2192 for ma in Pa.ModuleAutoGenList:\r
2193 ModuleCodaFile[(ma.MetaFile.File,ma.MetaFile.Root,ma.Arch,ma.MetaFile.Path)] = [item.Target for item in ma.CodaTargetList]\r
2194 Pa.DataPipe.DataContainer = {"ModuleCodaFile":ModuleCodaFile}\r
fc8b8dea 2195 # ModuleList contains all driver modules only\r
373298ca 2196 for Module in ModuleList:\r
fc8b8dea 2197 # Get ModuleAutoGen object to generate C code file and makefile\r
373298ca 2198 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
373298ca
FB
2199 if Ma is None:\r
2200 continue\r
2201 if Ma.PcdIsDriver:\r
2202 Ma.PlatformInfo = Pa\r
2203 Ma.Workspace = Wa\r
2204 PcdMaList.append(Ma)\r
fc8b8dea
SS
2205 self.AllDrivers.add(Ma)\r
2206 self.AllModules.add(Ma)\r
373298ca
FB
2207\r
2208 mqueue = mp.Queue()\r
fc8b8dea 2209 cqueue = mp.Queue()\r
373298ca
FB
2210 for m in Pa.GetAllModuleInfo:\r
2211 mqueue.put(m)\r
fc8b8dea
SS
2212 module_file,module_root,module_path,module_basename,\\r
2213 module_originalpath,module_arch,IsLib = m\r
2214 Ma = ModuleAutoGen(Wa, PathClass(module_path, Wa), BuildTarget,\\r
2215 ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
2216 self.AllModules.add(Ma)\r
373298ca
FB
2217 data_pipe_file = os.path.join(Pa.BuildDir, "GlobalVar_%s_%s.bin" % (str(Pa.Guid),Pa.Arch))\r
2218 Pa.DataPipe.dump(data_pipe_file)\r
2219\r
bfe36cb4 2220 mqueue.put((None,None,None,None,None,None,None))\r
fc8b8dea 2221 autogen_rt, errorcode = self.StartAutoGen(mqueue, Pa.DataPipe, self.SkipAutoGen, PcdMaList, cqueue)\r
373298ca
FB
2222\r
2223 if not autogen_rt:\r
2224 self.AutoGenMgr.TerminateWorkers()\r
2225 self.AutoGenMgr.join(1)\r
2226 raise FatalError(errorcode)\r
fc8b8dea
SS
2227\r
2228 if GlobalData.gUseHashCache:\r
2229 for item in GlobalData.gModuleAllCacheStatus:\r
2230 (MetaFilePath, Arch, CacheStr, Status) = item\r
2231 Ma = ModuleAutoGen(Wa, PathClass(MetaFilePath, Wa), BuildTarget,\\r
2232 ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
2233 if CacheStr == "PreMakeCache" and Status == False:\r
2234 self.PreMakeCacheMiss.add(Ma)\r
2235 if CacheStr == "PreMakeCache" and Status == True:\r
2236 self.PreMakeCacheHit.add(Ma)\r
2237 GlobalData.gModuleCacheHit.add(Ma)\r
2238 if CacheStr == "MakeCache" and Status == False:\r
2239 self.MakeCacheMiss.add(Ma)\r
2240 if CacheStr == "MakeCache" and Status == True:\r
2241 self.MakeCacheHit.add(Ma)\r
2242 GlobalData.gModuleCacheHit.add(Ma)\r
373298ca
FB
2243 self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
2244 AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")\r
2245 with open(AutoGenIdFile,"w") as fw:\r
2246 fw.write("Arch=%s\n" % "|".join((Wa.ArchList)))\r
2247 fw.write("BuildDir=%s\n" % Wa.BuildDir)\r
2248 fw.write("PlatformGuid=%s\n" % str(Wa.AutoGenObjectList[0].Guid))\r
fc8b8dea
SS
2249\r
2250 if GlobalData.gBinCacheSource:\r
2251 BuildModules.extend(self.MakeCacheMiss)\r
2252 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheDest:\r
2253 BuildModules.extend(self.PreMakeCacheMiss)\r
2254 else:\r
2255 BuildModules.extend(self.AllDrivers)\r
2256\r
373298ca
FB
2257 self.Progress.Stop("done!")\r
2258 return Wa, BuildModules\r
2259\r
52302d4d 2260 def _MultiThreadBuildPlatform(self):\r
f0dc69e6 2261 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
52302d4d 2262 for BuildTarget in self.BuildTargetList:\r
0d2711a6 2263 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 2264 index = 0\r
52302d4d 2265 for ToolChain in self.ToolChainList:\r
78fb6b0e 2266 resetFdsGlobalVariable()\r
0d2711a6 2267 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 2268 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
2269 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
2270 index += 1\r
52302d4d
LG
2271 ExitFlag = threading.Event()\r
2272 ExitFlag.clear()\r
373298ca
FB
2273 if self.SkipAutoGen:\r
2274 Wa = self.VerifyAutoGenFiles()\r
2275 if Wa is None:\r
5a9db858 2276 self.SkipAutoGen = False\r
373298ca 2277 Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)\r
0e7e7a26 2278 else:\r
373298ca
FB
2279 GlobalData.gAutoGenPhase = True\r
2280 self.BuildModules = self.SetupMakeSetting(Wa)\r
2281 else:\r
2282 Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)\r
2283 Pa = Wa.AutoGenObjectList[0]\r
2284 GlobalData.gAutoGenPhase = False\r
0e7e7a26
SS
2285\r
2286 if GlobalData.gBinCacheSource:\r
fc8b8dea
SS
2287 EdkLogger.quiet("[cache Summary]: Total module num: %s" % len(self.AllModules))\r
2288 EdkLogger.quiet("[cache Summary]: PreMakecache miss num: %s " % len(self.PreMakeCacheMiss))\r
2289 EdkLogger.quiet("[cache Summary]: Makecache miss num: %s " % len(self.MakeCacheMiss))\r
0e7e7a26 2290\r
673d09a2 2291 for Arch in Wa.ArchList:\r
1b8eca8b 2292 MakeStart = time.time()\r
0e7e7a26 2293 for Ma in set(self.BuildModules):\r
52302d4d 2294 # Generate build task for the module\r
a0a2cd1e 2295 if not Ma.IsBinaryModule:\r
673d09a2 2296 Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))\r
52302d4d
LG
2297 # Break build if any build thread has error\r
2298 if BuildTask.HasError():\r
2299 # we need a full version of makefile for platform\r
2300 ExitFlag.set()\r
2301 BuildTask.WaitForComplete()\r
2302 Pa.CreateMakeFile(False)\r
2303 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
2304 # Start task scheduler\r
2305 if not BuildTask.IsOnGoing():\r
2306 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
2307\r
2308 # in case there's an interruption. we need a full version of makefile for platform\r
373298ca 2309\r
52302d4d
LG
2310 if BuildTask.HasError():\r
2311 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1b8eca8b 2312 self.MakeTime += int(round((time.time() - MakeStart)))\r
52302d4d 2313\r
1b8eca8b 2314 MakeContiue = time.time()\r
64b2609f 2315 #\r
52302d4d
LG
2316 #\r
2317 # All modules have been put in build tasks queue. Tell task scheduler\r
2318 # to exit if all tasks are completed\r
2319 #\r
2320 ExitFlag.set()\r
2321 BuildTask.WaitForComplete()\r
b8ac0b7f 2322 if GlobalData.gBinCacheDest:\r
fc8b8dea
SS
2323 self.GenDestCache()\r
2324 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
2325 # Only for --hash\r
2326 # Update PreMakeCacheChain files\r
2327 self.GenLocalPreMakeCache()\r
e0f8261a
FZ
2328 #\r
2329 # Get Module List\r
2330 #\r
2331 ModuleList = {ma.Guid.upper(): ma for ma in self.BuildModules}\r
b8ac0b7f 2332 self.BuildModules = []\r
1b8eca8b 2333 self.MakeTime += int(round((time.time() - MakeContiue)))\r
52302d4d
LG
2334 #\r
2335 # Check for build error, and raise exception if one\r
2336 # has been signaled.\r
2337 #\r
2338 if BuildTask.HasError():\r
2339 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
2340\r
2341 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 2342 if self.Target in ["", "all", "fds"]:\r
0d2711a6 2343 for Arch in Wa.ArchList:\r
52302d4d
LG
2344 #\r
2345 # Check whether the set fix address is above 4G for 32bit image.\r
2346 #\r
2347 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
2348 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 2349\r
52302d4d
LG
2350 #\r
2351 # Rebase module to the preferred memory address before GenFds\r
2352 #\r
d943b0c3 2353 MapBuffer = []\r
636f2be6
LG
2354 if self.LoadFixAddress != 0:\r
2355 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d 2356\r
0d2711a6 2357 if self.Fdf:\r
f3decdc3
LG
2358 #\r
2359 # Generate FD image if there's a FDF file found\r
2360 #\r
1b8eca8b 2361 GenFdsStart = time.time()\r
370544d1
DL
2362 if GenFdsApi(Wa.GenFdsCommandDict, self.Db):\r
2363 EdkLogger.error("build", COMMAND_FAILURE)\r
3a3a3af4
FZ
2364 Threshold = self.GetFreeSizeThreshold()\r
2365 if Threshold:\r
2366 self.CheckFreeSizeThreshold(Threshold, Wa.FvDir)\r
03af2753 2367\r
52302d4d
LG
2368 #\r
2369 # Create MAP file for all platform FVs after GenFds.\r
2370 #\r
636f2be6 2371 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1b8eca8b 2372 self.GenFdsTime += int(round((time.time() - GenFdsStart)))\r
52302d4d
LG
2373 #\r
2374 # Save MAP buffer into MAP file.\r
2375 #\r
2376 self._SaveMapFile(MapBuffer, Wa)\r
373298ca 2377 self.CreateGuidedSectionToolsFile(Wa)\r
3a3a3af4
FZ
2378\r
2379 ## GetFreeSizeThreshold()\r
2380 #\r
2381 # @retval int Threshold value\r
2382 #\r
2383 def GetFreeSizeThreshold(self):\r
2384 Threshold = None\r
2385 Threshold_Str = GlobalData.gCommandLineDefines.get('FV_SPARE_SPACE_THRESHOLD')\r
2386 if Threshold_Str:\r
2387 try:\r
2388 if Threshold_Str.lower().startswith('0x'):\r
2389 Threshold = int(Threshold_Str, 16)\r
2390 else:\r
2391 Threshold = int(Threshold_Str)\r
2392 except:\r
2393 EdkLogger.warn("build", 'incorrect value for FV_SPARE_SPACE_THRESHOLD %s.Only decimal or hex format is allowed.' % Threshold_Str)\r
2394 return Threshold\r
2395\r
2396 def CheckFreeSizeThreshold(self, Threshold=None, FvDir=None):\r
2397 if not isinstance(Threshold, int):\r
2398 return\r
2399 if not isinstance(FvDir, str) or not FvDir:\r
2400 return\r
2401 FdfParserObject = GlobalData.gFdfParser\r
2402 FvRegionNameList = [FvName for FvName in FdfParserObject.Profile.FvDict if FdfParserObject.Profile.FvDict[FvName].FvRegionInFD]\r
2403 for FvName in FdfParserObject.Profile.FvDict:\r
2404 if FvName in FvRegionNameList:\r
2405 FvSpaceInfoFileName = os.path.join(FvDir, FvName.upper() + '.Fv.map')\r
2406 if os.path.exists(FvSpaceInfoFileName):\r
2407 FileLinesList = getlines(FvSpaceInfoFileName)\r
2408 for Line in FileLinesList:\r
2409 NameValue = Line.split('=')\r
2410 if len(NameValue) == 2 and NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':\r
2411 FreeSizeValue = int(NameValue[1].strip(), 0)\r
2412 if FreeSizeValue < Threshold:\r
2413 EdkLogger.error("build", FV_FREESIZE_ERROR,\r
2414 '%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
2415 FvName, FreeSizeValue, Threshold))\r
2416 break\r
2417\r
52302d4d
LG
2418 ## Generate GuidedSectionTools.txt in the FV directories.\r
2419 #\r
373298ca 2420 def CreateGuidedSectionToolsFile(self,Wa):\r
0d2711a6
LG
2421 for BuildTarget in self.BuildTargetList:\r
2422 for ToolChain in self.ToolChainList:\r
0d2711a6
LG
2423 FvDir = Wa.FvDir\r
2424 if not os.path.exists(FvDir):\r
2425 continue\r
2426\r
4afd3d04 2427 for Arch in self.ArchList:\r
52302d4d
LG
2428 # Look through the tool definitions for GUIDed tools\r
2429 guidAttribs = []\r
3a041437 2430 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.items():\r
ab957f03
MK
2431 GuidBuildTarget, GuidToolChain, GuidArch, GuidTool, GuidAttr = attrib.split('_')\r
2432 if GuidAttr.upper() == 'GUID':\r
2433 if GuidBuildTarget == TAB_STAR:\r
2434 GuidBuildTarget = BuildTarget\r
2435 if GuidToolChain == TAB_STAR:\r
2436 GuidToolChain = ToolChain\r
2437 if GuidArch == TAB_STAR:\r
2438 GuidArch = Arch\r
2439 if GuidBuildTarget == BuildTarget and GuidToolChain == ToolChain and GuidArch == Arch:\r
2440 path = '_'.join(attrib.split('_')[:-1]) + '_PATH'\r
2441 if path in self.ToolDef.ToolsDefTxtDictionary:\r
2442 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
2443 path = self.GetRealPathOfTool(path)\r
2444 guidAttribs.append((value.lower(), GuidTool, path))\r
2445 # Sort by GuidTool name\r
2446 sorted (guidAttribs, key=lambda x: x[1])\r
52302d4d
LG
2447 # Write out GuidedSecTools.txt\r
2448 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
2449 toolsFile = open(toolsFile, 'wt')\r
2450 for guidedSectionTool in guidAttribs:\r
72443dd2 2451 print(' '.join(guidedSectionTool), file=toolsFile)\r
52302d4d
LG
2452 toolsFile.close()\r
2453\r
8c944c93 2454 ## Returns the real path of the tool.\r
52302d4d 2455 #\r
8c944c93 2456 def GetRealPathOfTool (self, tool):\r
52302d4d
LG
2457 if os.path.exists(tool):\r
2458 return os.path.realpath(tool)\r
52302d4d
LG
2459 return tool\r
2460\r
2461 ## Launch the module or platform build\r
2462 #\r
2463 def Launch(self):\r
fc8b8dea
SS
2464 self.AllDrivers = set()\r
2465 self.AllModules = set()\r
2466 self.PreMakeCacheMiss = set()\r
2467 self.PreMakeCacheHit = set()\r
2468 self.MakeCacheMiss = set()\r
2469 self.MakeCacheHit = set()\r
0d2711a6 2470 if not self.ModuleFile:\r
52302d4d
LG
2471 if not self.SpawnMode or self.Target not in ["", "all"]:\r
2472 self.SpawnMode = False\r
2473 self._BuildPlatform()\r
2474 else:\r
2475 self._MultiThreadBuildPlatform()\r
52302d4d
LG
2476 else:\r
2477 self.SpawnMode = False\r
2478 self._BuildModule()\r
2479\r
bcbdc755 2480 if self.Target == 'cleanall':\r
bcbdc755
YL
2481 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)\r
2482\r
a0a2cd1e 2483 def CreateAsBuiltInf(self):\r
b8ac0b7f
BF
2484 for Module in self.BuildModules:\r
2485 Module.CreateAsBuiltInf()\r
2486\r
fc8b8dea
SS
2487 def GenDestCache(self):\r
2488 for Module in self.AllModules:\r
2489 Module.GenPreMakefileHashList()\r
2490 Module.GenMakefileHashList()\r
b8ac0b7f 2491 Module.CopyModuleToCache()\r
fc8b8dea
SS
2492\r
2493 def GenLocalPreMakeCache(self):\r
2494 for Module in self.PreMakeCacheMiss:\r
2495 Module.GenPreMakefileHashList()\r
2496\r
52302d4d
LG
2497 ## Do some clean-up works when error occurred\r
2498 def Relinquish(self):\r
2499 OldLogLevel = EdkLogger.GetLevel()\r
2500 EdkLogger.SetLevel(EdkLogger.ERROR)\r
52302d4d
LG
2501 Utils.Progressor.Abort()\r
2502 if self.SpawnMode == True:\r
2503 BuildTask.Abort()\r
2504 EdkLogger.SetLevel(OldLogLevel)\r
2505\r
52302d4d
LG
2506def ParseDefines(DefineList=[]):\r
2507 DefineDict = {}\r
4231a819 2508 if DefineList is not None:\r
52302d4d
LG
2509 for Define in DefineList:\r
2510 DefineTokenList = Define.split("=", 1)\r
0d2711a6
LG
2511 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):\r
2512 EdkLogger.error('build', FORMAT_INVALID,\r
2513 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",\r
2514 ExtraData=DefineTokenList[0])\r
4afd3d04 2515\r
52302d4d 2516 if len(DefineTokenList) == 1:\r
0d2711a6 2517 DefineDict[DefineTokenList[0]] = "TRUE"\r
52302d4d
LG
2518 else:\r
2519 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
2520 return DefineDict\r
2521\r
c60fb00f 2522\r
52302d4d 2523\r
1b8eca8b
YZ
2524def LogBuildTime(Time):\r
2525 if Time:\r
2526 TimeDurStr = ''\r
2527 TimeDur = time.gmtime(Time)\r
2528 if TimeDur.tm_yday > 1:\r
2529 TimeDurStr = time.strftime("%H:%M:%S", TimeDur) + ", %d day(s)" % (TimeDur.tm_yday - 1)\r
2530 else:\r
2531 TimeDurStr = time.strftime("%H:%M:%S", TimeDur)\r
2532 return TimeDurStr\r
2533 else:\r
2534 return None\r
1a624dd7 2535def ThreadNum():\r
4465cd12
FZ
2536 OptionParser = MyOptionParser()\r
2537 if not OptionParser.BuildOption and not OptionParser.BuildTarget:\r
2538 OptionParser.GetOption()\r
2539 BuildOption, BuildTarget = OptionParser.BuildOption, OptionParser.BuildTarget\r
1a624dd7 2540 ThreadNumber = BuildOption.ThreadNumber\r
4465cd12 2541 GlobalData.gCmdConfDir = BuildOption.ConfDirectory\r
1a624dd7 2542 if ThreadNumber is None:\r
4465cd12
FZ
2543 TargetObj = TargetTxtDict()\r
2544 ThreadNumber = TargetObj.Target.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
1a624dd7
FB
2545 if ThreadNumber == '':\r
2546 ThreadNumber = 0\r
2547 else:\r
2548 ThreadNumber = int(ThreadNumber, 0)\r
1b8eca8b 2549\r
1a624dd7
FB
2550 if ThreadNumber == 0:\r
2551 try:\r
2552 ThreadNumber = multiprocessing.cpu_count()\r
2553 except (ImportError, NotImplementedError):\r
2554 ThreadNumber = 1\r
2555 return ThreadNumber\r
52302d4d
LG
2556## Tool entrance method\r
2557#\r
2558# This method mainly dispatch specific methods per the command line options.\r
2559# If no error found, return zero value so the caller of this tool can know\r
2560# if it's executed successfully or not.\r
2561#\r
2562# @retval 0 Tool was successful\r
2563# @retval 1 Tool failed\r
2564#\r
1a624dd7 2565LogQMaxSize = ThreadNum() * 10\r
52302d4d
LG
2566def Main():\r
2567 StartTime = time.time()\r
2568\r
636ed13a
FB
2569 #\r
2570 # Create a log Queue\r
2571 #\r
1a624dd7 2572 LogQ = mp.Queue(LogQMaxSize)\r
52302d4d 2573 # Initialize log system\r
636ed13a 2574 EdkLogger.LogClientInitialize(LogQ)\r
f0dc69e6 2575 GlobalData.gCommand = sys.argv[1:]\r
52302d4d
LG
2576 #\r
2577 # Parse the options and args\r
2578 #\r
4465cd12
FZ
2579 OptionParser = MyOptionParser()\r
2580 if not OptionParser.BuildOption and not OptionParser.BuildTarget:\r
2581 OptionParser.GetOption()\r
2582 Option, Target = OptionParser.BuildOption, OptionParser.BuildTarget\r
52302d4d
LG
2583 GlobalData.gOptions = Option\r
2584 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
2585\r
2586 # Set log level\r
636ed13a 2587 LogLevel = EdkLogger.INFO\r
4231a819 2588 if Option.verbose is not None:\r
52302d4d 2589 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
636ed13a 2590 LogLevel = EdkLogger.VERBOSE\r
4231a819 2591 elif Option.quiet is not None:\r
52302d4d 2592 EdkLogger.SetLevel(EdkLogger.QUIET)\r
636ed13a 2593 LogLevel = EdkLogger.QUIET\r
4231a819 2594 elif Option.debug is not None:\r
52302d4d 2595 EdkLogger.SetLevel(Option.debug + 1)\r
636ed13a 2596 LogLevel = Option.debug + 1\r
52302d4d
LG
2597 else:\r
2598 EdkLogger.SetLevel(EdkLogger.INFO)\r
2599\r
52302d4d
LG
2600 if Option.WarningAsError == True:\r
2601 EdkLogger.SetWarningAsError()\r
636ed13a
FB
2602 Log_Agent = LogAgent(LogQ,LogLevel,Option.LogFile)\r
2603 Log_Agent.start()\r
52302d4d
LG
2604\r
2605 if platform.platform().find("Windows") >= 0:\r
2606 GlobalData.gIsWindows = True\r
2607 else:\r
2608 GlobalData.gIsWindows = False\r
2609\r
6780eef1
LG
2610 EdkLogger.quiet("Build environment: %s" % platform.platform())\r
2611 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));\r
52302d4d
LG
2612 ReturnCode = 0\r
2613 MyBuild = None\r
09ae0f11 2614 BuildError = True\r
52302d4d
LG
2615 try:\r
2616 if len(Target) == 0:\r
2617 Target = "all"\r
2618 elif len(Target) >= 2:\r
2619 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
47fea6af 2620 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d
LG
2621 else:\r
2622 Target = Target[0].lower()\r
2623\r
2624 if Target not in gSupportedTarget:\r
2625 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
47fea6af 2626 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d 2627\r
52302d4d
LG
2628 #\r
2629 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
2630 #\r
2631 CheckEnvVariable()\r
0d2711a6
LG
2632 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))\r
2633\r
52302d4d
LG
2634 Workspace = os.getenv("WORKSPACE")\r
2635 #\r
2636 # Get files real name in workspace dir\r
2637 #\r
2638 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
2639\r
2640 WorkingDirectory = os.getcwd()\r
2641 if not Option.ModuleFile:\r
2642 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
2643 FileNum = len(FileList)\r
2644 if FileNum >= 2:\r
2645 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
2646 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
2647 elif FileNum == 1:\r
2648 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
2649\r
2650 if Option.ModuleFile:\r
2651 if os.path.isabs (Option.ModuleFile):\r
2652 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
2653 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
2654 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
2655 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
2656 if ErrorCode != 0:\r
2657 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2658\r
4231a819 2659 if Option.PlatformFile is not None:\r
52302d4d
LG
2660 if os.path.isabs (Option.PlatformFile):\r
2661 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
2662 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
2663 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
52302d4d 2664\r
4231a819 2665 if Option.FdfFile is not None:\r
52302d4d
LG
2666 if os.path.isabs (Option.FdfFile):\r
2667 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
2668 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
2669 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
2670 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
2671 if ErrorCode != 0:\r
2672 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2673\r
4231a819 2674 if Option.Flag is not None and Option.Flag not in ['-c', '-s']:\r
f3decdc3
LG
2675 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
2676\r
636ed13a 2677 MyBuild = Build(Target, Workspace, Option,LogQ)\r
64b2609f 2678 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)\r
f0dc69e6
YZ
2679 if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):\r
2680 MyBuild.Launch()\r
2f818ed0 2681\r
09ae0f11
YL
2682 #\r
2683 # All job done, no error found and no exception raised\r
2684 #\r
2685 BuildError = False\r
5b0671c1 2686 except FatalError as X:\r
4231a819 2687 if MyBuild is not None:\r
52302d4d
LG
2688 # for multi-thread build exits safely\r
2689 MyBuild.Relinquish()\r
4231a819 2690 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2691 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2692 ReturnCode = X.args[0]\r
5b0671c1 2693 except Warning as X:\r
52302d4d 2694 # error from Fdf parser\r
4231a819 2695 if MyBuild is not None:\r
52302d4d
LG
2696 # for multi-thread build exits safely\r
2697 MyBuild.Relinquish()\r
4231a819 2698 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2699 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2700 else:\r
47fea6af 2701 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
52302d4d
LG
2702 ReturnCode = FORMAT_INVALID\r
2703 except KeyboardInterrupt:\r
673d09a2
FB
2704 if MyBuild is not None:\r
2705\r
2706 # for multi-thread build exits safely\r
2707 MyBuild.Relinquish()\r
52302d4d 2708 ReturnCode = ABORT_ERROR\r
4231a819 2709 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2710 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2711 except:\r
4231a819 2712 if MyBuild is not None:\r
52302d4d
LG
2713 # for multi-thread build exits safely\r
2714 MyBuild.Relinquish()\r
2715\r
2716 # try to get the meta-file from the object causing exception\r
2717 Tb = sys.exc_info()[-1]\r
2718 MetaFile = GlobalData.gProcessingFile\r
4231a819 2719 while Tb is not None:\r
52302d4d
LG
2720 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
2721 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
2722 Tb = Tb.tb_next\r
2723 EdkLogger.error(\r
2724 "\nbuild",\r
2725 CODE_ERROR,\r
2726 "Unknown fatal error when processing [%s]" % MetaFile,\r
c1387446 2727 ExtraData="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR,\r
52302d4d
LG
2728 RaiseError=False\r
2729 )\r
d0acc87a 2730 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
52302d4d
LG
2731 ReturnCode = CODE_ERROR\r
2732 finally:\r
2733 Utils.Progressor.Abort()\r
97fa0ee9 2734 Utils.ClearDuplicatedInf()\r
52302d4d
LG
2735\r
2736 if ReturnCode == 0:\r
f0dc69e6 2737 try:\r
91048b0d 2738 MyBuild.LaunchPostbuild()\r
f0dc69e6
YZ
2739 Conclusion = "Done"\r
2740 except:\r
2741 Conclusion = "Failed"\r
52302d4d
LG
2742 elif ReturnCode == ABORT_ERROR:\r
2743 Conclusion = "Aborted"\r
2744 else:\r
2745 Conclusion = "Failed"\r
2746 FinishTime = time.time()\r
4234283c
LG
2747 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))\r
2748 BuildDurationStr = ""\r
2749 if BuildDuration.tm_yday > 1:\r
47fea6af 2750 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)\r
4234283c
LG
2751 else:\r
2752 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)\r
4231a819 2753 if MyBuild is not None:\r
09ae0f11 2754 if not BuildError:\r
1b8eca8b 2755 MyBuild.BuildReport.GenerateReport(BuildDurationStr, LogBuildTime(MyBuild.AutoGenTime), LogBuildTime(MyBuild.MakeTime), LogBuildTime(MyBuild.GenFdsTime))\r
2f818ed0 2756\r
52302d4d 2757 EdkLogger.SetLevel(EdkLogger.QUIET)\r
6780eef1
LG
2758 EdkLogger.quiet("\n- %s -" % Conclusion)\r
2759 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
4234283c 2760 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
636ed13a
FB
2761 Log_Agent.kill()\r
2762 Log_Agent.join()\r
52302d4d
LG
2763 return ReturnCode\r
2764\r
2765if __name__ == '__main__':\r
673d09a2
FB
2766 try:\r
2767 mp.set_start_method('spawn')\r
2768 except:\r
2769 pass\r
52302d4d
LG
2770 r = Main()\r
2771 ## 0-127 is a safe return range, and 1 is a standard default error\r
2772 if r < 0 or r > 127: r = 1\r
2773 sys.exit(r)\r