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