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