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