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