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