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