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