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