]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/Python/build/build.py
BaseTools: update the mail address for stack trace info
[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 - 2016, Intel Corporation. All rights reserved.<BR>\r
6#\r
7# This program and the accompanying materials\r
8# are licensed and made available under the terms and conditions of the BSD License\r
9# which accompanies this distribution. The full text of the license may be found at\r
10# http://opensource.org/licenses/bsd-license.php\r
11#\r
12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14#\r
15\r
16##\r
17# Import Modules\r
18#\r
19import Common.LongFilePathOs as os\r
20import re\r
21import StringIO\r
22import sys\r
23import glob\r
24import time\r
25import platform\r
26import traceback\r
27import encodings.ascii\r
28\r
29from struct import *\r
30from threading import *\r
31from optparse import OptionParser\r
32from subprocess import *\r
33from Common import Misc as Utils\r
34\r
35from Common.LongFilePathSupport import OpenLongFilePath as open\r
36from Common.LongFilePathSupport import LongFilePath\r
37from Common.TargetTxtClassObject import *\r
38from Common.ToolDefClassObject import *\r
39from Common.DataType import *\r
40from Common.BuildVersion import gBUILD_VERSION\r
41from AutoGen.AutoGen import *\r
42from Common.BuildToolError import *\r
43from Workspace.WorkspaceDatabase import *\r
44from Common.MultipleWorkspace import MultipleWorkspace as mws\r
45\r
46from BuildReport import BuildReport\r
47from GenPatchPcdTable.GenPatchPcdTable import *\r
48from PatchPcdValue.PatchPcdValue import *\r
49\r
50import Common.EdkLogger\r
51import Common.GlobalData as GlobalData\r
52\r
53# Version and Copyright\r
54VersionNumber = "0.60" + ' ' + gBUILD_VERSION\r
55__version__ = "%prog Version " + VersionNumber\r
56__copyright__ = "Copyright (c) 2007 - 2014, Intel Corporation All rights reserved."\r
57\r
58## standard targets of build command\r
59gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']\r
60\r
61## build configuration file\r
62gBuildConfiguration = "target.txt"\r
63gToolsDefinition = "tools_def.txt"\r
64\r
65TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$')\r
66TmpTableDict = {}\r
67\r
68## Check environment PATH variable to make sure the specified tool is found\r
69#\r
70# If the tool is found in the PATH, then True is returned\r
71# Otherwise, False is returned\r
72#\r
73def IsToolInPath(tool):\r
74 if os.environ.has_key('PATHEXT'):\r
75 extns = os.environ['PATHEXT'].split(os.path.pathsep)\r
76 else:\r
77 extns = ('',)\r
78 for pathDir in os.environ['PATH'].split(os.path.pathsep):\r
79 for ext in extns:\r
80 if os.path.exists(os.path.join(pathDir, tool + ext)):\r
81 return True\r
82 return False\r
83\r
84## Check environment variables\r
85#\r
86# Check environment variables that must be set for build. Currently they are\r
87#\r
88# WORKSPACE The directory all packages/platforms start from\r
89# EDK_TOOLS_PATH The directory contains all tools needed by the build\r
90# PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH\r
91#\r
92# If any of above environment variable is not set or has error, the build\r
93# will be broken.\r
94#\r
95def CheckEnvVariable():\r
96 # check WORKSPACE\r
97 if "WORKSPACE" not in os.environ:\r
98 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
99 ExtraData="WORKSPACE")\r
100\r
101 WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))\r
102 if not os.path.exists(WorkspaceDir):\r
103 EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir)\r
104 elif ' ' in WorkspaceDir:\r
105 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",\r
106 ExtraData=WorkspaceDir)\r
107 os.environ["WORKSPACE"] = WorkspaceDir\r
108 \r
109 # set multiple workspace\r
110 PackagesPath = os.getenv("PACKAGES_PATH")\r
111 mws.setWs(WorkspaceDir, PackagesPath)\r
112\r
113 #\r
114 # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP\r
115 #\r
116 if "ECP_SOURCE" not in os.environ:\r
117 os.environ["ECP_SOURCE"] = mws.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)\r
118 if "EFI_SOURCE" not in os.environ:\r
119 os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"]\r
120 if "EDK_SOURCE" not in os.environ:\r
121 os.environ["EDK_SOURCE"] = os.environ["ECP_SOURCE"]\r
122\r
123 #\r
124 # Unify case of characters on case-insensitive systems\r
125 #\r
126 EfiSourceDir = os.path.normcase(os.path.normpath(os.environ["EFI_SOURCE"]))\r
127 EdkSourceDir = os.path.normcase(os.path.normpath(os.environ["EDK_SOURCE"]))\r
128 EcpSourceDir = os.path.normcase(os.path.normpath(os.environ["ECP_SOURCE"]))\r
129\r
130 os.environ["EFI_SOURCE"] = EfiSourceDir\r
131 os.environ["EDK_SOURCE"] = EdkSourceDir\r
132 os.environ["ECP_SOURCE"] = EcpSourceDir\r
133 os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])\r
134\r
135 if not os.path.exists(EcpSourceDir):\r
136 EdkLogger.verbose("ECP_SOURCE = %s doesn't exist. Edk modules could not be built." % EcpSourceDir)\r
137 elif ' ' in EcpSourceDir:\r
138 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in ECP_SOURCE path",\r
139 ExtraData=EcpSourceDir)\r
140 if not os.path.exists(EdkSourceDir):\r
141 if EdkSourceDir == EcpSourceDir:\r
142 EdkLogger.verbose("EDK_SOURCE = %s doesn't exist. Edk modules could not be built." % EdkSourceDir)\r
143 else:\r
144 EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE does not exist",\r
145 ExtraData=EdkSourceDir)\r
146 elif ' ' in EdkSourceDir:\r
147 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EDK_SOURCE path",\r
148 ExtraData=EdkSourceDir)\r
149 if not os.path.exists(EfiSourceDir):\r
150 if EfiSourceDir == EcpSourceDir:\r
151 EdkLogger.verbose("EFI_SOURCE = %s doesn't exist. Edk modules could not be built." % EfiSourceDir)\r
152 else:\r
153 EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE does not exist",\r
154 ExtraData=EfiSourceDir)\r
155 elif ' ' in EfiSourceDir:\r
156 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EFI_SOURCE path",\r
157 ExtraData=EfiSourceDir)\r
158\r
159 # check those variables on single workspace case\r
160 if not PackagesPath:\r
161 # change absolute path to relative path to WORKSPACE\r
162 if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
163 EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE",\r
164 ExtraData="WORKSPACE = %s\n EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir))\r
165 if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
166 EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE",\r
167 ExtraData="WORKSPACE = %s\n EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir))\r
168 if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
169 EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE",\r
170 ExtraData="WORKSPACE = %s\n ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir))\r
171\r
172 # check EDK_TOOLS_PATH\r
173 if "EDK_TOOLS_PATH" not in os.environ:\r
174 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
175 ExtraData="EDK_TOOLS_PATH")\r
176\r
177 # check PATH\r
178 if "PATH" not in os.environ:\r
179 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
180 ExtraData="PATH")\r
181\r
182 GlobalData.gWorkspace = WorkspaceDir\r
183 GlobalData.gEfiSource = EfiSourceDir\r
184 GlobalData.gEdkSource = EdkSourceDir\r
185 GlobalData.gEcpSource = EcpSourceDir\r
186\r
187 GlobalData.gGlobalDefines["WORKSPACE"] = WorkspaceDir\r
188 GlobalData.gGlobalDefines["EFI_SOURCE"] = EfiSourceDir\r
189 GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir\r
190 GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir\r
191 GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]\r
192 \r
193## Get normalized file path\r
194#\r
195# Convert the path to be local format, and remove the WORKSPACE path at the\r
196# beginning if the file path is given in full path.\r
197#\r
198# @param FilePath File path to be normalized\r
199# @param Workspace Workspace path which the FilePath will be checked against\r
200#\r
201# @retval string The normalized file path\r
202#\r
203def NormFile(FilePath, Workspace):\r
204 # check if the path is absolute or relative\r
205 if os.path.isabs(FilePath):\r
206 FileFullPath = os.path.normpath(FilePath)\r
207 else:\r
208 FileFullPath = os.path.normpath(mws.join(Workspace, FilePath))\r
209 Workspace = mws.getWs(Workspace, FilePath)\r
210\r
211 # check if the file path exists or not\r
212 if not os.path.isfile(FileFullPath):\r
213 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath)\r
214\r
215 # remove workspace directory from the beginning part of the file path\r
216 if Workspace[-1] in ["\\", "/"]:\r
217 return FileFullPath[len(Workspace):]\r
218 else:\r
219 return FileFullPath[(len(Workspace) + 1):]\r
220\r
221## Get the output of an external program\r
222#\r
223# This is the entrance method of thread reading output of an external program and\r
224# putting them in STDOUT/STDERR of current program.\r
225#\r
226# @param From The stream message read from\r
227# @param To The stream message put on\r
228# @param ExitFlag The flag used to indicate stopping reading\r
229#\r
230def ReadMessage(From, To, ExitFlag):\r
231 while True:\r
232 # read one line a time\r
233 Line = From.readline()\r
234 # empty string means "end"\r
235 if Line != None and Line != "":\r
236 To(Line.rstrip())\r
237 else:\r
238 break\r
239 if ExitFlag.isSet():\r
240 break\r
241\r
242## Launch an external program\r
243#\r
244# This method will call subprocess.Popen to execute an external program with\r
245# given options in specified directory. Because of the dead-lock issue during\r
246# redirecting output of the external program, threads are used to to do the\r
247# redirection work.\r
248#\r
249# @param Command A list or string containing the call of the program\r
250# @param WorkingDir The directory in which the program will be running\r
251#\r
252def LaunchCommand(Command, WorkingDir):\r
253 # if working directory doesn't exist, Popen() will raise an exception\r
254 if not os.path.isdir(WorkingDir):\r
255 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)\r
256 \r
257 # Command is used as the first Argument in following Popen().\r
258 # It could be a string or sequence. We find that if command is a string in following Popen(),\r
259 # ubuntu may fail with an error message that the command is not found.\r
260 # So here we may need convert command from string to list instance.\r
261 if not isinstance(Command, list):\r
262 if platform.system() != 'Windows':\r
263 Command = Command.split()\r
264\r
265 Proc = None\r
266 EndOfProcedure = None\r
267 try:\r
268 # launch the command\r
269 Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1)\r
270\r
271 # launch two threads to read the STDOUT and STDERR\r
272 EndOfProcedure = Event()\r
273 EndOfProcedure.clear()\r
274 if Proc.stdout:\r
275 StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))\r
276 StdOutThread.setName("STDOUT-Redirector")\r
277 StdOutThread.setDaemon(False)\r
278 StdOutThread.start()\r
279\r
280 if Proc.stderr:\r
281 StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))\r
282 StdErrThread.setName("STDERR-Redirector")\r
283 StdErrThread.setDaemon(False)\r
284 StdErrThread.start()\r
285\r
286 # waiting for program exit\r
287 Proc.wait()\r
288 except: # in case of aborting\r
289 # terminate the threads redirecting the program output\r
290 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
291 if EndOfProcedure != None:\r
292 EndOfProcedure.set()\r
293 if Proc == None:\r
294 if type(Command) != type(""):\r
295 Command = " ".join(Command)\r
296 EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))\r
297\r
298 if Proc.stdout:\r
299 StdOutThread.join()\r
300 if Proc.stderr:\r
301 StdErrThread.join()\r
302\r
303 # check the return code of the program\r
304 if Proc.returncode != 0:\r
305 if type(Command) != type(""):\r
306 Command = " ".join(Command)\r
307 EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))\r
308\r
309## The smallest unit that can be built in multi-thread build mode\r
310#\r
311# This is the base class of build unit. The "Obj" parameter must provide\r
312# __str__(), __eq__() and __hash__() methods. Otherwise there could be build units\r
313# missing build.\r
314#\r
315# Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.\r
316#\r
317class BuildUnit:\r
318 ## The constructor\r
319 #\r
320 # @param self The object pointer\r
321 # @param Obj The object the build is working on\r
322 # @param Target The build target name, one of gSupportedTarget\r
323 # @param Dependency The BuildUnit(s) which must be completed in advance\r
324 # @param WorkingDir The directory build command starts in\r
325 #\r
326 def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):\r
327 self.BuildObject = Obj\r
328 self.Dependency = Dependency\r
329 self.WorkingDir = WorkingDir\r
330 self.Target = Target\r
331 self.BuildCommand = BuildCommand\r
332 if not BuildCommand:\r
333 EdkLogger.error("build", OPTION_MISSING,\r
334 "No build command found for this module. "\r
335 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
336 (Obj.BuildTarget, Obj.ToolChain, Obj.Arch),\r
337 ExtraData=str(Obj))\r
338\r
339\r
340 ## str() method\r
341 #\r
342 # It just returns the string representation of self.BuildObject\r
343 #\r
344 # @param self The object pointer\r
345 #\r
346 def __str__(self):\r
347 return str(self.BuildObject)\r
348\r
349 ## "==" operator method\r
350 #\r
351 # It just compares self.BuildObject with "Other". So self.BuildObject must\r
352 # provide its own __eq__() method.\r
353 #\r
354 # @param self The object pointer\r
355 # @param Other The other BuildUnit object compared to\r
356 #\r
357 def __eq__(self, Other):\r
358 return Other != None and self.BuildObject == Other.BuildObject \\r
359 and self.BuildObject.Arch == Other.BuildObject.Arch\r
360\r
361 ## hash() method\r
362 #\r
363 # It just returns the hash value of self.BuildObject which must be hashable.\r
364 #\r
365 # @param self The object pointer\r
366 #\r
367 def __hash__(self):\r
368 return hash(self.BuildObject) + hash(self.BuildObject.Arch)\r
369\r
370 def __repr__(self):\r
371 return repr(self.BuildObject)\r
372\r
373## The smallest module unit that can be built by nmake/make command in multi-thread build mode\r
374#\r
375# This class is for module build by nmake/make build system. The "Obj" parameter\r
376# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could\r
377# be make units missing build.\r
378#\r
379# Currently the "Obj" should be only ModuleAutoGen object.\r
380#\r
381class ModuleMakeUnit(BuildUnit):\r
382 ## The constructor\r
383 #\r
384 # @param self The object pointer\r
385 # @param Obj The ModuleAutoGen object the build is working on\r
386 # @param Target The build target name, one of gSupportedTarget\r
387 #\r
388 def __init__(self, Obj, Target):\r
389 Dependency = [ModuleMakeUnit(La, Target) for La in Obj.LibraryAutoGenList]\r
390 BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)\r
391 if Target in [None, "", "all"]:\r
392 self.Target = "tbuild"\r
393\r
394## The smallest platform unit that can be built by nmake/make command in multi-thread build mode\r
395#\r
396# This class is for platform build by nmake/make build system. The "Obj" parameter\r
397# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could\r
398# be make units missing build.\r
399#\r
400# Currently the "Obj" should be only PlatformAutoGen object.\r
401#\r
402class PlatformMakeUnit(BuildUnit):\r
403 ## The constructor\r
404 #\r
405 # @param self The object pointer\r
406 # @param Obj The PlatformAutoGen object the build is working on\r
407 # @param Target The build target name, one of gSupportedTarget\r
408 #\r
409 def __init__(self, Obj, Target):\r
410 Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.LibraryAutoGenList]\r
411 Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.ModuleAutoGenList])\r
412 BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)\r
413\r
414## The class representing the task of a module build or platform build\r
415#\r
416# This class manages the build tasks in multi-thread build mode. Its jobs include\r
417# scheduling thread running, catching thread error, monitor the thread status, etc.\r
418#\r
419class BuildTask:\r
420 # queue for tasks waiting for schedule\r
421 _PendingQueue = sdict()\r
422 _PendingQueueLock = threading.Lock()\r
423\r
424 # queue for tasks ready for running\r
425 _ReadyQueue = sdict()\r
426 _ReadyQueueLock = threading.Lock()\r
427\r
428 # queue for run tasks\r
429 _RunningQueue = sdict()\r
430 _RunningQueueLock = threading.Lock()\r
431\r
432 # queue containing all build tasks, in case duplicate build\r
433 _TaskQueue = sdict()\r
434\r
435 # flag indicating error occurs in a running thread\r
436 _ErrorFlag = threading.Event()\r
437 _ErrorFlag.clear()\r
438 _ErrorMessage = ""\r
439\r
440 # BoundedSemaphore object used to control the number of running threads\r
441 _Thread = None\r
442\r
443 # flag indicating if the scheduler is started or not\r
444 _SchedulerStopped = threading.Event()\r
445 _SchedulerStopped.set()\r
446\r
447 ## Start the task scheduler thread\r
448 #\r
449 # @param MaxThreadNumber The maximum thread number\r
450 # @param ExitFlag Flag used to end the scheduler\r
451 #\r
452 @staticmethod\r
453 def StartScheduler(MaxThreadNumber, ExitFlag):\r
454 SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))\r
455 SchedulerThread.setName("Build-Task-Scheduler")\r
456 SchedulerThread.setDaemon(False)\r
457 SchedulerThread.start()\r
458 # wait for the scheduler to be started, especially useful in Linux\r
459 while not BuildTask.IsOnGoing():\r
460 time.sleep(0.01)\r
461\r
462 ## Scheduler method\r
463 #\r
464 # @param MaxThreadNumber The maximum thread number\r
465 # @param ExitFlag Flag used to end the scheduler\r
466 #\r
467 @staticmethod\r
468 def Scheduler(MaxThreadNumber, ExitFlag):\r
469 BuildTask._SchedulerStopped.clear()\r
470 try:\r
471 # use BoundedSemaphore to control the maximum running threads\r
472 BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)\r
473 #\r
474 # scheduling loop, which will exits when no pending/ready task and\r
475 # indicated to do so, or there's error in running thread\r
476 #\r
477 while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \\r
478 or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():\r
479 EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"\r
480 % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))\r
481\r
482 # get all pending tasks\r
483 BuildTask._PendingQueueLock.acquire()\r
484 BuildObjectList = BuildTask._PendingQueue.keys()\r
485 #\r
486 # check if their dependency is resolved, and if true, move them\r
487 # into ready queue\r
488 #\r
489 for BuildObject in BuildObjectList:\r
490 Bt = BuildTask._PendingQueue[BuildObject]\r
491 if Bt.IsReady():\r
492 BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)\r
493 BuildTask._PendingQueueLock.release()\r
494\r
495 # launch build thread until the maximum number of threads is reached\r
496 while not BuildTask._ErrorFlag.isSet():\r
497 # empty ready queue, do nothing further\r
498 if len(BuildTask._ReadyQueue) == 0:\r
499 break\r
500\r
501 # wait for active thread(s) exit\r
502 BuildTask._Thread.acquire(True)\r
503\r
504 # start a new build thread\r
505 Bo = BuildTask._ReadyQueue.keys()[0]\r
506 Bt = BuildTask._ReadyQueue.pop(Bo)\r
507\r
508 # move into running queue\r
509 BuildTask._RunningQueueLock.acquire()\r
510 BuildTask._RunningQueue[Bo] = Bt\r
511 BuildTask._RunningQueueLock.release()\r
512\r
513 Bt.Start()\r
514 # avoid tense loop\r
515 time.sleep(0.01)\r
516\r
517 # avoid tense loop\r
518 time.sleep(0.01)\r
519\r
520 # wait for all running threads exit\r
521 if BuildTask._ErrorFlag.isSet():\r
522 EdkLogger.quiet("\nWaiting for all build threads exit...")\r
523 # while not BuildTask._ErrorFlag.isSet() and \\r
524 while len(BuildTask._RunningQueue) > 0:\r
525 EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))\r
526 EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join([Th.getName() for Th in threading.enumerate()]))\r
527 # avoid tense loop\r
528 time.sleep(0.1)\r
529 except BaseException, X:\r
530 #\r
531 # TRICK: hide the output of threads left runing, so that the user can\r
532 # catch the error message easily\r
533 #\r
534 EdkLogger.SetLevel(EdkLogger.ERROR)\r
535 BuildTask._ErrorFlag.set()\r
536 BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)\r
537\r
538 BuildTask._PendingQueue.clear()\r
539 BuildTask._ReadyQueue.clear()\r
540 BuildTask._RunningQueue.clear()\r
541 BuildTask._TaskQueue.clear()\r
542 BuildTask._SchedulerStopped.set()\r
543\r
544 ## Wait for all running method exit\r
545 #\r
546 @staticmethod\r
547 def WaitForComplete():\r
548 BuildTask._SchedulerStopped.wait()\r
549\r
550 ## Check if the scheduler is running or not\r
551 #\r
552 @staticmethod\r
553 def IsOnGoing():\r
554 return not BuildTask._SchedulerStopped.isSet()\r
555\r
556 ## Abort the build\r
557 @staticmethod\r
558 def Abort():\r
559 if BuildTask.IsOnGoing():\r
560 BuildTask._ErrorFlag.set()\r
561 BuildTask.WaitForComplete()\r
562\r
563 ## Check if there's error in running thread\r
564 #\r
565 # Since the main thread cannot catch exceptions in other thread, we have to\r
566 # use threading.Event to communicate this formation to main thread.\r
567 #\r
568 @staticmethod\r
569 def HasError():\r
570 return BuildTask._ErrorFlag.isSet()\r
571\r
572 ## Get error message in running thread\r
573 #\r
574 # Since the main thread cannot catch exceptions in other thread, we have to\r
575 # use a static variable to communicate this message to main thread.\r
576 #\r
577 @staticmethod\r
578 def GetErrorMessage():\r
579 return BuildTask._ErrorMessage\r
580\r
581 ## Factory method to create a BuildTask object\r
582 #\r
583 # This method will check if a module is building or has been built. And if\r
584 # true, just return the associated BuildTask object in the _TaskQueue. If\r
585 # not, create and return a new BuildTask object. The new BuildTask object\r
586 # will be appended to the _PendingQueue for scheduling later.\r
587 #\r
588 # @param BuildItem A BuildUnit object representing a build object\r
589 # @param Dependency The dependent build object of BuildItem\r
590 #\r
591 @staticmethod\r
592 def New(BuildItem, Dependency=None):\r
593 if BuildItem in BuildTask._TaskQueue:\r
594 Bt = BuildTask._TaskQueue[BuildItem]\r
595 return Bt\r
596\r
597 Bt = BuildTask()\r
598 Bt._Init(BuildItem, Dependency)\r
599 BuildTask._TaskQueue[BuildItem] = Bt\r
600\r
601 BuildTask._PendingQueueLock.acquire()\r
602 BuildTask._PendingQueue[BuildItem] = Bt\r
603 BuildTask._PendingQueueLock.release()\r
604\r
605 return Bt\r
606\r
607 ## The real constructor of BuildTask\r
608 #\r
609 # @param BuildItem A BuildUnit object representing a build object\r
610 # @param Dependency The dependent build object of BuildItem\r
611 #\r
612 def _Init(self, BuildItem, Dependency=None):\r
613 self.BuildItem = BuildItem\r
614\r
615 self.DependencyList = []\r
616 if Dependency == None:\r
617 Dependency = BuildItem.Dependency\r
618 else:\r
619 Dependency.extend(BuildItem.Dependency)\r
620 self.AddDependency(Dependency)\r
621 # flag indicating build completes, used to avoid unnecessary re-build\r
622 self.CompleteFlag = False\r
623\r
624 ## Check if all dependent build tasks are completed or not\r
625 #\r
626 def IsReady(self):\r
627 ReadyFlag = True\r
628 for Dep in self.DependencyList:\r
629 if Dep.CompleteFlag == True:\r
630 continue\r
631 ReadyFlag = False\r
632 break\r
633\r
634 return ReadyFlag\r
635\r
636 ## Add dependent build task\r
637 #\r
638 # @param Dependency The list of dependent build objects\r
639 #\r
640 def AddDependency(self, Dependency):\r
641 for Dep in Dependency:\r
642 if not Dep.BuildObject.IsBinaryModule:\r
643 self.DependencyList.append(BuildTask.New(Dep)) # BuildTask list\r
644\r
645 ## The thread wrapper of LaunchCommand function\r
646 #\r
647 # @param Command A list or string contains the call of the command\r
648 # @param WorkingDir The directory in which the program will be running\r
649 #\r
650 def _CommandThread(self, Command, WorkingDir):\r
651 try:\r
652 LaunchCommand(Command, WorkingDir)\r
653 self.CompleteFlag = True\r
654 except:\r
655 #\r
656 # TRICK: hide the output of threads left runing, so that the user can\r
657 # catch the error message easily\r
658 #\r
659 if not BuildTask._ErrorFlag.isSet():\r
660 GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),\r
661 self.BuildItem.BuildObject.Arch,\r
662 self.BuildItem.BuildObject.ToolChain,\r
663 self.BuildItem.BuildObject.BuildTarget\r
664 )\r
665 EdkLogger.SetLevel(EdkLogger.ERROR)\r
666 BuildTask._ErrorFlag.set()\r
667 BuildTask._ErrorMessage = "%s broken\n %s [%s]" % \\r
668 (threading.currentThread().getName(), Command, WorkingDir)\r
669 # indicate there's a thread is available for another build task\r
670 BuildTask._RunningQueueLock.acquire()\r
671 BuildTask._RunningQueue.pop(self.BuildItem)\r
672 BuildTask._RunningQueueLock.release()\r
673 BuildTask._Thread.release()\r
674\r
675 ## Start build task thread\r
676 #\r
677 def Start(self):\r
678 EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))\r
679 Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]\r
680 self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))\r
681 self.BuildTread.setName("build thread")\r
682 self.BuildTread.setDaemon(False)\r
683 self.BuildTread.start()\r
684\r
685## The class contains the information related to EFI image\r
686#\r
687class PeImageInfo():\r
688 ## Constructor\r
689 #\r
690 # Constructor will load all required image information.\r
691 #\r
692 # @param BaseName The full file path of image.\r
693 # @param Guid The GUID for image.\r
694 # @param Arch Arch of this image.\r
695 # @param OutputDir The output directory for image.\r
696 # @param DebugDir The debug directory for image.\r
697 # @param ImageClass PeImage Information\r
698 #\r
699 def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass):\r
700 self.BaseName = BaseName\r
701 self.Guid = Guid\r
702 self.Arch = Arch\r
703 self.OutputDir = OutputDir\r
704 self.DebugDir = DebugDir\r
705 self.Image = ImageClass\r
706 self.Image.Size = (self.Image.Size / 0x1000 + 1) * 0x1000\r
707\r
708## The class implementing the EDK2 build process\r
709#\r
710# The build process includes:\r
711# 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf\r
712# 2. Parse DSC file of active platform\r
713# 3. Parse FDF file if any\r
714# 4. Establish build database, including parse all other files (module, package)\r
715# 5. Create AutoGen files (C code file, depex file, makefile) if necessary\r
716# 6. Call build command\r
717#\r
718class Build():\r
719 ## Constructor\r
720 #\r
721 # Constructor will load all necessary configurations, parse platform, modules\r
722 # and packages and the establish a database for AutoGen.\r
723 #\r
724 # @param Target The build command target, one of gSupportedTarget\r
725 # @param WorkspaceDir The directory of workspace\r
726 # @param BuildOptions Build options passed from command line\r
727 #\r
728 def __init__(self, Target, WorkspaceDir, BuildOptions):\r
729 self.WorkspaceDir = WorkspaceDir\r
730 self.Target = Target\r
731 self.PlatformFile = BuildOptions.PlatformFile\r
732 self.ModuleFile = BuildOptions.ModuleFile\r
733 self.ArchList = BuildOptions.TargetArch\r
734 self.ToolChainList = BuildOptions.ToolChain\r
735 self.BuildTargetList= BuildOptions.BuildTarget\r
736 self.Fdf = BuildOptions.FdfFile\r
737 self.FdList = BuildOptions.RomImage\r
738 self.FvList = BuildOptions.FvImage\r
739 self.CapList = BuildOptions.CapName\r
740 self.SilentMode = BuildOptions.SilentMode\r
741 self.ThreadNumber = BuildOptions.ThreadNumber\r
742 self.SkipAutoGen = BuildOptions.SkipAutoGen\r
743 self.Reparse = BuildOptions.Reparse\r
744 self.SkuId = BuildOptions.SkuId\r
745 self.ConfDirectory = BuildOptions.ConfDirectory\r
746 self.SpawnMode = True\r
747 self.BuildReport = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)\r
748 self.TargetTxt = TargetTxtClassObject()\r
749 self.ToolDef = ToolDefClassObject()\r
750 #Set global flag for build mode\r
751 GlobalData.gIgnoreSource = BuildOptions.IgnoreSources\r
752\r
753 if self.ConfDirectory:\r
754 # Get alternate Conf location, if it is absolute, then just use the absolute directory name\r
755 ConfDirectoryPath = os.path.normpath(self.ConfDirectory)\r
756\r
757 if not os.path.isabs(ConfDirectoryPath):\r
758 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE\r
759 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf\r
760 ConfDirectoryPath = mws.join(self.WorkspaceDir, ConfDirectoryPath)\r
761 else:\r
762 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf\r
763 ConfDirectoryPath = mws.join(self.WorkspaceDir, 'Conf')\r
764 GlobalData.gConfDirectory = ConfDirectoryPath\r
765 GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))\r
766\r
767 if BuildOptions.DisableCache:\r
768 self.Db = WorkspaceDatabase(":memory:")\r
769 else:\r
770 self.Db = WorkspaceDatabase(GlobalData.gDatabasePath, self.Reparse)\r
771 self.BuildDatabase = self.Db.BuildObject\r
772 self.Platform = None\r
773 self.LoadFixAddress = 0\r
774 self.UniFlag = BuildOptions.Flag\r
775 self.BuildModules = []\r
776\r
777 # print dot character during doing some time-consuming work\r
778 self.Progress = Utils.Progressor()\r
779\r
780 self.InitBuild()\r
781\r
782 # print current build environment and configuration\r
783 EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))\r
784 if "PACKAGES_PATH" in os.environ:\r
785 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env. \r
786 EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))\r
787 EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))\r
788 EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))\r
789 EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))\r
790 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))\r
791 if "EDK_TOOLS_BIN" in os.environ:\r
792 # Print the same path style with WORKSPACE env. \r
793 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))\r
794\r
795 EdkLogger.info("")\r
796\r
797 os.chdir(self.WorkspaceDir)\r
798\r
799 ## Load configuration\r
800 #\r
801 # This method will parse target.txt and get the build configurations.\r
802 #\r
803 def LoadConfiguration(self):\r
804 #\r
805 # Check target.txt and tools_def.txt and Init them\r
806 #\r
807 BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))\r
808 if os.path.isfile(BuildConfigurationFile) == True:\r
809 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)\r
810\r
811 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
812 if ToolDefinitionFile == '':\r
813 ToolDefinitionFile = gToolsDefinition\r
814 ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))\r
815 if os.path.isfile(ToolDefinitionFile) == True:\r
816 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)\r
817 else:\r
818 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)\r
819 else:\r
820 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
821\r
822 # if no ARCH given in command line, get it from target.txt\r
823 if not self.ArchList:\r
824 self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]\r
825 self.ArchList = tuple(self.ArchList)\r
826\r
827 # if no build target given in command line, get it from target.txt\r
828 if not self.BuildTargetList:\r
829 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]\r
830\r
831 # if no tool chain given in command line, get it from target.txt\r
832 if not self.ToolChainList:\r
833 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
834 if self.ToolChainList == None or len(self.ToolChainList) == 0:\r
835 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")\r
836\r
837 # check if the tool chains are defined or not\r
838 NewToolChainList = []\r
839 for ToolChain in self.ToolChainList:\r
840 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
841 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)\r
842 else:\r
843 NewToolChainList.append(ToolChain)\r
844 # if no tool chain available, break the build\r
845 if len(NewToolChainList) == 0:\r
846 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
847 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))\r
848 else:\r
849 self.ToolChainList = NewToolChainList\r
850\r
851 if self.ThreadNumber == None:\r
852 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
853 if self.ThreadNumber == '':\r
854 self.ThreadNumber = 0\r
855 else:\r
856 self.ThreadNumber = int(self.ThreadNumber, 0)\r
857\r
858 if self.ThreadNumber == 0:\r
859 self.ThreadNumber = 1\r
860\r
861 if not self.PlatformFile:\r
862 PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
863 if not PlatformFile:\r
864 # Try to find one in current directory\r
865 WorkingDirectory = os.getcwd()\r
866 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
867 FileNum = len(FileList)\r
868 if FileNum >= 2:\r
869 EdkLogger.error("build", OPTION_MISSING,\r
870 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
871 elif FileNum == 1:\r
872 PlatformFile = FileList[0]\r
873 else:\r
874 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
875 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
876\r
877 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
878\r
879 ## Initialize build configuration\r
880 #\r
881 # This method will parse DSC file and merge the configurations from\r
882 # command line and target.txt, then get the final build configurations.\r
883 #\r
884 def InitBuild(self):\r
885 # parse target.txt, tools_def.txt, and platform file\r
886 self.LoadConfiguration()\r
887\r
888 # Allow case-insensitive for those from command line or configuration file\r
889 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
890 if ErrorCode != 0:\r
891 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
892\r
893 # create metafile database\r
894 self.Db.InitDatabase()\r
895\r
896 ## Build a module or platform\r
897 #\r
898 # Create autogen code and makefile for a module or platform, and the launch\r
899 # "make" command to build it\r
900 #\r
901 # @param Target The target of build command\r
902 # @param Platform The platform file\r
903 # @param Module The module file\r
904 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
905 # @param ToolChain The name of toolchain to build\r
906 # @param Arch The arch of the module/platform\r
907 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
908 # for dependent modules/Libraries\r
909 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
910 # for dependent modules/Libraries\r
911 #\r
912 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
913 if AutoGenObject == None:\r
914 return False\r
915\r
916 # skip file generation for cleanxxx targets, run and fds target\r
917 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
918 # for target which must generate AutoGen code and makefile\r
919 if not self.SkipAutoGen or Target == 'genc':\r
920 self.Progress.Start("Generating code")\r
921 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
922 self.Progress.Stop("done!")\r
923 if Target == "genc":\r
924 return True\r
925\r
926 if not self.SkipAutoGen or Target == 'genmake':\r
927 self.Progress.Start("Generating makefile")\r
928 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
929 self.Progress.Stop("done!")\r
930 if Target == "genmake":\r
931 return True\r
932 else:\r
933 # always recreate top/platform makefile when clean, just in case of inconsistency\r
934 AutoGenObject.CreateCodeFile(False)\r
935 AutoGenObject.CreateMakeFile(False)\r
936\r
937 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
938 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
939\r
940 BuildCommand = AutoGenObject.BuildCommand\r
941 if BuildCommand == None or len(BuildCommand) == 0:\r
942 EdkLogger.error("build", OPTION_MISSING,\r
943 "No build command found for this module. "\r
944 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
945 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
946 ExtraData=str(AutoGenObject))\r
947\r
948 makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]\r
949\r
950 # run\r
951 if Target == 'run':\r
952 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
953 Command = '.\SecMain'\r
954 os.chdir(RunDir)\r
955 LaunchCommand(Command, RunDir)\r
956 return True\r
957\r
958 # build modules\r
959 if BuildModule:\r
960 BuildCommand = BuildCommand + [Target]\r
961 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
962 self.CreateAsBuiltInf()\r
963 return True\r
964\r
965 # build library\r
966 if Target == 'libraries':\r
967 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
968 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
969 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
970 return True\r
971\r
972 # build module\r
973 if Target == 'modules':\r
974 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
975 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
976 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
977 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
978 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']\r
979 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
980 self.CreateAsBuiltInf()\r
981 return True\r
982\r
983 # cleanlib\r
984 if Target == 'cleanlib':\r
985 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
986 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
987 if os.path.exists(LibMakefile):\r
988 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
989 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
990 return True\r
991\r
992 # clean\r
993 if Target == 'clean':\r
994 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
995 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))\r
996 if os.path.exists(ModMakefile):\r
997 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']\r
998 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
999 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1000 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1001 if os.path.exists(LibMakefile):\r
1002 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1003 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1004 return True\r
1005\r
1006 # cleanall\r
1007 if Target == 'cleanall':\r
1008 try:\r
1009 #os.rmdir(AutoGenObject.BuildDir)\r
1010 RemoveDirectory(AutoGenObject.BuildDir, True)\r
1011 except WindowsError, X:\r
1012 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1013 return True\r
1014\r
1015 ## Build a module or platform\r
1016 #\r
1017 # Create autogen code and makefile for a module or platform, and the launch\r
1018 # "make" command to build it\r
1019 #\r
1020 # @param Target The target of build command\r
1021 # @param Platform The platform file\r
1022 # @param Module The module file\r
1023 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1024 # @param ToolChain The name of toolchain to build\r
1025 # @param Arch The arch of the module/platform\r
1026 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1027 # for dependent modules/Libraries\r
1028 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1029 # for dependent modules/Libraries\r
1030 #\r
1031 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
1032 if AutoGenObject == None:\r
1033 return False\r
1034\r
1035 # skip file generation for cleanxxx targets, run and fds target\r
1036 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1037 # for target which must generate AutoGen code and makefile\r
1038 if not self.SkipAutoGen or Target == 'genc':\r
1039 self.Progress.Start("Generating code")\r
1040 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1041 self.Progress.Stop("done!")\r
1042 if Target == "genc":\r
1043 return True\r
1044\r
1045 if not self.SkipAutoGen or Target == 'genmake':\r
1046 self.Progress.Start("Generating makefile")\r
1047 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
1048 #AutoGenObject.CreateAsBuiltInf()\r
1049 self.Progress.Stop("done!")\r
1050 if Target == "genmake":\r
1051 return True\r
1052 else:\r
1053 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1054 AutoGenObject.CreateCodeFile(False)\r
1055 AutoGenObject.CreateMakeFile(False)\r
1056\r
1057 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1058 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1059\r
1060 BuildCommand = AutoGenObject.BuildCommand\r
1061 if BuildCommand == None or len(BuildCommand) == 0:\r
1062 EdkLogger.error("build", OPTION_MISSING,\r
1063 "No build command found for this module. "\r
1064 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
1065 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1066 ExtraData=str(AutoGenObject))\r
1067\r
1068 # build modules\r
1069 if BuildModule:\r
1070 if Target != 'fds':\r
1071 BuildCommand = BuildCommand + [Target]\r
1072 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
1073 self.CreateAsBuiltInf()\r
1074 return True\r
1075\r
1076 # genfds\r
1077 if Target == 'fds':\r
1078 LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)\r
1079 return True\r
1080\r
1081 # run\r
1082 if Target == 'run':\r
1083 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
1084 Command = '.\SecMain'\r
1085 os.chdir(RunDir)\r
1086 LaunchCommand(Command, RunDir)\r
1087 return True\r
1088\r
1089 # build library\r
1090 if Target == 'libraries':\r
1091 pass\r
1092\r
1093 # not build modules\r
1094\r
1095\r
1096 # cleanall\r
1097 if Target == 'cleanall':\r
1098 try:\r
1099 #os.rmdir(AutoGenObject.BuildDir)\r
1100 RemoveDirectory(AutoGenObject.BuildDir, True)\r
1101 except WindowsError, X:\r
1102 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1103 return True\r
1104\r
1105 ## Rebase module image and Get function address for the input module list.\r
1106 #\r
1107 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
1108 if ModeIsSmm:\r
1109 AddrIsOffset = False\r
1110 InfFileNameList = ModuleList.keys()\r
1111 #InfFileNameList.sort()\r
1112 for InfFile in InfFileNameList:\r
1113 sys.stdout.write (".")\r
1114 sys.stdout.flush()\r
1115 ModuleInfo = ModuleList[InfFile]\r
1116 ModuleName = ModuleInfo.BaseName\r
1117 ModuleOutputImage = ModuleInfo.Image.FileName\r
1118 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')\r
1119 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1120 if not ModeIsSmm:\r
1121 BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
1122 #\r
1123 # Update Image to new BaseAddress by GenFw tool\r
1124 #\r
1125 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
1126 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
1127 else:\r
1128 #\r
1129 # Set new address to the section header only for SMM driver.\r
1130 #\r
1131 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
1132 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
1133 #\r
1134 # Collect funtion address from Map file\r
1135 #\r
1136 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')\r
1137 FunctionList = []\r
1138 if os.path.exists(ImageMapTable):\r
1139 OrigImageBaseAddress = 0\r
1140 ImageMap = open(ImageMapTable, 'r')\r
1141 for LinStr in ImageMap:\r
1142 if len (LinStr.strip()) == 0:\r
1143 continue\r
1144 #\r
1145 # Get the preferred address set on link time.\r
1146 #\r
1147 if LinStr.find ('Preferred load address is') != -1:\r
1148 StrList = LinStr.split()\r
1149 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
1150\r
1151 StrList = LinStr.split()\r
1152 if len (StrList) > 4:\r
1153 if StrList[3] == 'f' or StrList[3] == 'F':\r
1154 Name = StrList[1]\r
1155 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
1156 FunctionList.append ((Name, RelativeAddress))\r
1157 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):\r
1158 #\r
1159 # Get the real entry point address for IPF image.\r
1160 #\r
1161 ModuleInfo.Image.EntryPoint = RelativeAddress\r
1162 ImageMap.close()\r
1163 #\r
1164 # Add general information.\r
1165 #\r
1166 if ModeIsSmm:\r
1167 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1168 elif AddrIsOffset:\r
1169 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
1170 else:\r
1171 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1172 #\r
1173 # Add guid and general seciton section.\r
1174 #\r
1175 TextSectionAddress = 0\r
1176 DataSectionAddress = 0\r
1177 for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
1178 if SectionHeader[0] == '.text':\r
1179 TextSectionAddress = SectionHeader[1]\r
1180 elif SectionHeader[0] in ['.data', '.sdata']:\r
1181 DataSectionAddress = SectionHeader[1]\r
1182 if AddrIsOffset:\r
1183 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))\r
1184 else:\r
1185 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
1186 #\r
1187 # Add debug image full path.\r
1188 #\r
1189 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
1190 #\r
1191 # Add funtion address\r
1192 #\r
1193 for Function in FunctionList:\r
1194 if AddrIsOffset:\r
1195 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
1196 else:\r
1197 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))\r
1198 ImageMap.close()\r
1199\r
1200 #\r
1201 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1202 #\r
1203 if ModeIsSmm:\r
1204 BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
1205\r
1206 ## Collect MAP information of all FVs\r
1207 #\r
1208 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):\r
1209 if self.Fdf:\r
1210 # First get the XIP base address for FV map file.\r
1211 GuidPattern = re.compile("[-a-fA-F0-9]+")\r
1212 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")\r
1213 for FvName in Wa.FdfProfile.FvDict.keys():\r
1214 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
1215 if not os.path.exists(FvMapBuffer):\r
1216 continue\r
1217 FvMap = open(FvMapBuffer, 'r')\r
1218 #skip FV size information\r
1219 FvMap.readline()\r
1220 FvMap.readline()\r
1221 FvMap.readline()\r
1222 FvMap.readline()\r
1223 for Line in FvMap:\r
1224 MatchGuid = GuidPattern.match(Line)\r
1225 if MatchGuid != None:\r
1226 #\r
1227 # Replace GUID with module name\r
1228 #\r
1229 GuidString = MatchGuid.group()\r
1230 if GuidString.upper() in ModuleList:\r
1231 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
1232 MapBuffer.write('%s' % (Line))\r
1233 #\r
1234 # Add the debug image full path.\r
1235 #\r
1236 MatchGuid = GuidName.match(Line)\r
1237 if MatchGuid != None:\r
1238 GuidString = MatchGuid.group().split("=")[1]\r
1239 if GuidString.upper() in ModuleList:\r
1240 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
1241\r
1242 FvMap.close()\r
1243\r
1244 ## Collect MAP information of all modules\r
1245 #\r
1246 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
1247 sys.stdout.write ("Generate Load Module At Fix Address Map")\r
1248 sys.stdout.flush()\r
1249 PatchEfiImageList = []\r
1250 PeiModuleList = {}\r
1251 BtModuleList = {}\r
1252 RtModuleList = {}\r
1253 SmmModuleList = {}\r
1254 PeiSize = 0\r
1255 BtSize = 0\r
1256 RtSize = 0\r
1257 # reserve 4K size in SMRAM to make SMM module address not from 0.\r
1258 SmmSize = 0x1000\r
1259 IsIpfPlatform = False\r
1260 if 'IPF' in self.ArchList:\r
1261 IsIpfPlatform = True\r
1262 for ModuleGuid in ModuleList:\r
1263 Module = ModuleList[ModuleGuid]\r
1264 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
1265\r
1266 OutputImageFile = ''\r
1267 for ResultFile in Module.CodaTargetList:\r
1268 if str(ResultFile.Target).endswith('.efi'):\r
1269 #\r
1270 # module list for PEI, DXE, RUNTIME and SMM\r
1271 #\r
1272 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
1273 ImageClass = PeImageClass (OutputImageFile)\r
1274 if not ImageClass.IsValid:\r
1275 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
1276 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)\r
1277 if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER', 'PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:\r
1278 PeiModuleList[Module.MetaFile] = ImageInfo\r
1279 PeiSize += ImageInfo.Image.Size\r
1280 elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:\r
1281 BtModuleList[Module.MetaFile] = ImageInfo\r
1282 BtSize += ImageInfo.Image.Size\r
1283 elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:\r
1284 RtModuleList[Module.MetaFile] = ImageInfo\r
1285 #IPF runtime driver needs to be at 2 page alignment.\r
1286 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:\r
1287 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000\r
1288 RtSize += ImageInfo.Image.Size\r
1289 elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:\r
1290 SmmModuleList[Module.MetaFile] = ImageInfo\r
1291 SmmSize += ImageInfo.Image.Size\r
1292 if Module.ModuleType == 'DXE_SMM_DRIVER':\r
1293 PiSpecVersion = '0x00000000'\r
1294 if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:\r
1295 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']\r
1296 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
1297 if int(PiSpecVersion, 16) < 0x0001000A:\r
1298 BtModuleList[Module.MetaFile] = ImageInfo\r
1299 BtSize += ImageInfo.Image.Size\r
1300 break\r
1301 #\r
1302 # EFI image is final target.\r
1303 # Check EFI image contains patchable FixAddress related PCDs.\r
1304 #\r
1305 if OutputImageFile != '':\r
1306 ModuleIsPatch = False\r
1307 for Pcd in Module.ModulePcdList:\r
1308 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1309 ModuleIsPatch = True\r
1310 break\r
1311 if not ModuleIsPatch:\r
1312 for Pcd in Module.LibraryPcdList:\r
1313 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1314 ModuleIsPatch = True\r
1315 break\r
1316\r
1317 if not ModuleIsPatch:\r
1318 continue\r
1319 #\r
1320 # Module includes the patchable load fix address PCDs.\r
1321 # It will be fixed up later.\r
1322 #\r
1323 PatchEfiImageList.append (OutputImageFile)\r
1324\r
1325 #\r
1326 # Get Top Memory address\r
1327 #\r
1328 ReservedRuntimeMemorySize = 0\r
1329 TopMemoryAddress = 0\r
1330 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
1331 TopMemoryAddress = 0\r
1332 else:\r
1333 TopMemoryAddress = self.LoadFixAddress\r
1334 if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
1335 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
1336 # Make IPF runtime driver at 2 page alignment.\r
1337 if IsIpfPlatform:\r
1338 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000\r
1339 RtSize = RtSize + ReservedRuntimeMemorySize\r
1340\r
1341 #\r
1342 # Patch FixAddress related PCDs into EFI image\r
1343 #\r
1344 for EfiImage in PatchEfiImageList:\r
1345 EfiImageMap = EfiImage.replace('.efi', '.map')\r
1346 if not os.path.exists(EfiImageMap):\r
1347 continue\r
1348 #\r
1349 # Get PCD offset in EFI image by GenPatchPcdTable function\r
1350 #\r
1351 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)\r
1352 #\r
1353 # Patch real PCD value by PatchPcdValue tool\r
1354 #\r
1355 for PcdInfo in PcdTable:\r
1356 ReturnValue = 0\r
1357 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
1358 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000))\r
1359 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
1360 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000))\r
1361 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
1362 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000))\r
1363 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
1364 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000))\r
1365 if ReturnValue != 0:\r
1366 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
1367\r
1368 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize / 0x1000))\r
1369 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize / 0x1000))\r
1370 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize / 0x1000))\r
1371 if len (SmmModuleList) > 0:\r
1372 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize / 0x1000))\r
1373\r
1374 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
1375 BtBaseAddr = TopMemoryAddress - RtSize\r
1376 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize\r
1377\r
1378 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
1379 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
1380 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
1381 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)\r
1382 MapBuffer.write('\n\n')\r
1383 sys.stdout.write ("\n")\r
1384 sys.stdout.flush()\r
1385\r
1386 ## Save platform Map file\r
1387 #\r
1388 def _SaveMapFile (self, MapBuffer, Wa):\r
1389 #\r
1390 # Map file path is got.\r
1391 #\r
1392 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
1393 #\r
1394 # Save address map into MAP file.\r
1395 #\r
1396 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
1397 MapBuffer.close()\r
1398 if self.LoadFixAddress != 0:\r
1399 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))\r
1400 sys.stdout.flush()\r
1401\r
1402 ## Build active platform for different build targets and different tool chains\r
1403 #\r
1404 def _BuildPlatform(self):\r
1405 for BuildTarget in self.BuildTargetList:\r
1406 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
1407 for ToolChain in self.ToolChainList:\r
1408 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1409 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
1410 Wa = WorkspaceAutoGen(\r
1411 self.WorkspaceDir,\r
1412 self.PlatformFile,\r
1413 BuildTarget,\r
1414 ToolChain,\r
1415 self.ArchList,\r
1416 self.BuildDatabase,\r
1417 self.TargetTxt,\r
1418 self.ToolDef,\r
1419 self.Fdf,\r
1420 self.FdList,\r
1421 self.FvList,\r
1422 self.CapList,\r
1423 self.SkuId,\r
1424 self.UniFlag,\r
1425 self.Progress\r
1426 )\r
1427 self.Fdf = Wa.FdfFile\r
1428 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
1429 self.BuildReport.AddPlatformReport(Wa)\r
1430 self.Progress.Stop("done!")\r
1431 for Arch in Wa.ArchList:\r
1432 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1433 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1434 for Module in Pa.Platform.Modules:\r
1435 # Get ModuleAutoGen object to generate C code file and makefile\r
1436 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1437 if Ma == None:\r
1438 continue\r
1439 self.BuildModules.append(Ma)\r
1440 self._BuildPa(self.Target, Pa)\r
1441\r
1442 # Create MAP file when Load Fix Address is enabled.\r
1443 if self.Target in ["", "all", "fds"]:\r
1444 for Arch in Wa.ArchList:\r
1445 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1446 #\r
1447 # Check whether the set fix address is above 4G for 32bit image.\r
1448 #\r
1449 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1450 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
1451 #\r
1452 # Get Module List\r
1453 #\r
1454 ModuleList = {}\r
1455 for Pa in Wa.AutoGenObjectList:\r
1456 for Ma in Pa.ModuleAutoGenList:\r
1457 if Ma == None:\r
1458 continue\r
1459 if not Ma.IsLibrary:\r
1460 ModuleList[Ma.Guid.upper()] = Ma\r
1461\r
1462 MapBuffer = StringIO('')\r
1463 if self.LoadFixAddress != 0:\r
1464 #\r
1465 # Rebase module to the preferred memory address before GenFds\r
1466 #\r
1467 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1468 if self.Fdf:\r
1469 #\r
1470 # create FDS again for the updated EFI image\r
1471 #\r
1472 self._Build("fds", Wa)\r
1473 #\r
1474 # Create MAP file for all platform FVs after GenFds.\r
1475 #\r
1476 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1477 #\r
1478 # Save MAP buffer into MAP file.\r
1479 #\r
1480 self._SaveMapFile (MapBuffer, Wa)\r
1481\r
1482 ## Build active module for different build targets, different tool chains and different archs\r
1483 #\r
1484 def _BuildModule(self):\r
1485 for BuildTarget in self.BuildTargetList:\r
1486 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
1487 for ToolChain in self.ToolChainList:\r
1488 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1489 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
1490 #\r
1491 # module build needs platform build information, so get platform\r
1492 # AutoGen first\r
1493 #\r
1494 Wa = WorkspaceAutoGen(\r
1495 self.WorkspaceDir,\r
1496 self.PlatformFile,\r
1497 BuildTarget,\r
1498 ToolChain,\r
1499 self.ArchList,\r
1500 self.BuildDatabase,\r
1501 self.TargetTxt,\r
1502 self.ToolDef,\r
1503 self.Fdf,\r
1504 self.FdList,\r
1505 self.FvList,\r
1506 self.CapList,\r
1507 self.SkuId,\r
1508 self.UniFlag,\r
1509 self.Progress,\r
1510 self.ModuleFile\r
1511 )\r
1512 self.Fdf = Wa.FdfFile\r
1513 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
1514 Wa.CreateMakeFile(False)\r
1515 self.Progress.Stop("done!")\r
1516 MaList = []\r
1517 for Arch in Wa.ArchList:\r
1518 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1519 Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1520 if Ma == None: continue\r
1521 MaList.append(Ma)\r
1522 self.BuildModules.append(Ma)\r
1523 if not Ma.IsBinaryModule:\r
1524 self._Build(self.Target, Ma, BuildModule=True)\r
1525\r
1526 self.BuildReport.AddPlatformReport(Wa, MaList)\r
1527 if MaList == []:\r
1528 EdkLogger.error(\r
1529 'build',\r
1530 BUILD_ERROR,\r
1531 "Module for [%s] is not a component of active platform."\\r
1532 " Please make sure that the ARCH and inf file path are"\\r
1533 " given in the same as in [%s]" % \\r
1534 (', '.join(Wa.ArchList), self.PlatformFile),\r
1535 ExtraData=self.ModuleFile\r
1536 )\r
1537 # Create MAP file when Load Fix Address is enabled.\r
1538 if self.Target == "fds" and self.Fdf:\r
1539 for Arch in Wa.ArchList:\r
1540 #\r
1541 # Check whether the set fix address is above 4G for 32bit image.\r
1542 #\r
1543 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1544 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
1545 #\r
1546 # Get Module List\r
1547 #\r
1548 ModuleList = {}\r
1549 for Pa in Wa.AutoGenObjectList:\r
1550 for Ma in Pa.ModuleAutoGenList:\r
1551 if Ma == None:\r
1552 continue\r
1553 if not Ma.IsLibrary:\r
1554 ModuleList[Ma.Guid.upper()] = Ma\r
1555\r
1556 MapBuffer = StringIO('')\r
1557 if self.LoadFixAddress != 0:\r
1558 #\r
1559 # Rebase module to the preferred memory address before GenFds\r
1560 #\r
1561 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1562 #\r
1563 # create FDS again for the updated EFI image\r
1564 #\r
1565 self._Build("fds", Wa)\r
1566 #\r
1567 # Create MAP file for all platform FVs after GenFds.\r
1568 #\r
1569 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1570 #\r
1571 # Save MAP buffer into MAP file.\r
1572 #\r
1573 self._SaveMapFile (MapBuffer, Wa)\r
1574\r
1575 ## Build a platform in multi-thread mode\r
1576 #\r
1577 def _MultiThreadBuildPlatform(self):\r
1578 for BuildTarget in self.BuildTargetList:\r
1579 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
1580 for ToolChain in self.ToolChainList:\r
1581 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1582 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
1583 Wa = WorkspaceAutoGen(\r
1584 self.WorkspaceDir,\r
1585 self.PlatformFile,\r
1586 BuildTarget,\r
1587 ToolChain,\r
1588 self.ArchList,\r
1589 self.BuildDatabase,\r
1590 self.TargetTxt,\r
1591 self.ToolDef,\r
1592 self.Fdf,\r
1593 self.FdList,\r
1594 self.FvList,\r
1595 self.CapList,\r
1596 self.SkuId,\r
1597 self.UniFlag,\r
1598 self.Progress\r
1599 )\r
1600 self.Fdf = Wa.FdfFile\r
1601 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
1602 self.BuildReport.AddPlatformReport(Wa)\r
1603 Wa.CreateMakeFile(False)\r
1604\r
1605 # multi-thread exit flag\r
1606 ExitFlag = threading.Event()\r
1607 ExitFlag.clear()\r
1608 for Arch in Wa.ArchList:\r
1609 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1610 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1611 if Pa == None:\r
1612 continue\r
1613 ModuleList = []\r
1614 for Inf in Pa.Platform.Modules:\r
1615 ModuleList.append(Inf)\r
1616 # Add the INF only list in FDF\r
1617 if GlobalData.gFdfParser != None:\r
1618 for InfName in GlobalData.gFdfParser.Profile.InfList:\r
1619 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)\r
1620 if Inf in Pa.Platform.Modules:\r
1621 continue\r
1622 ModuleList.append(Inf)\r
1623 for Module in ModuleList:\r
1624 # Get ModuleAutoGen object to generate C code file and makefile\r
1625 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1626 \r
1627 if Ma == None:\r
1628 continue\r
1629 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1630 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1631 # for target which must generate AutoGen code and makefile\r
1632 if not self.SkipAutoGen or self.Target == 'genc':\r
1633 Ma.CreateCodeFile(True)\r
1634 if self.Target == "genc":\r
1635 continue\r
1636\r
1637 if not self.SkipAutoGen or self.Target == 'genmake':\r
1638 Ma.CreateMakeFile(True)\r
1639 if self.Target == "genmake":\r
1640 continue\r
1641 self.BuildModules.append(Ma)\r
1642 self.Progress.Stop("done!")\r
1643\r
1644 for Ma in self.BuildModules:\r
1645 # Generate build task for the module\r
1646 if not Ma.IsBinaryModule:\r
1647 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
1648 # Break build if any build thread has error\r
1649 if BuildTask.HasError():\r
1650 # we need a full version of makefile for platform\r
1651 ExitFlag.set()\r
1652 BuildTask.WaitForComplete()\r
1653 Pa.CreateMakeFile(False)\r
1654 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1655 # Start task scheduler\r
1656 if not BuildTask.IsOnGoing():\r
1657 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1658\r
1659 # in case there's an interruption. we need a full version of makefile for platform\r
1660 Pa.CreateMakeFile(False)\r
1661 if BuildTask.HasError():\r
1662 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1663\r
1664 #\r
1665 # Save temp tables to a TmpTableDict.\r
1666 #\r
1667 for Key in Wa.BuildDatabase._CACHE_:\r
1668 if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:\r
1669 if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):\r
1670 TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur\r
1671 #\r
1672 #\r
1673 # All modules have been put in build tasks queue. Tell task scheduler\r
1674 # to exit if all tasks are completed\r
1675 #\r
1676 ExitFlag.set()\r
1677 BuildTask.WaitForComplete()\r
1678 self.CreateAsBuiltInf()\r
1679\r
1680 #\r
1681 # Check for build error, and raise exception if one\r
1682 # has been signaled.\r
1683 #\r
1684 if BuildTask.HasError():\r
1685 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1686\r
1687 # Create MAP file when Load Fix Address is enabled.\r
1688 if self.Target in ["", "all", "fds"]:\r
1689 for Arch in Wa.ArchList:\r
1690 #\r
1691 # Check whether the set fix address is above 4G for 32bit image.\r
1692 #\r
1693 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1694 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
1695 #\r
1696 # Get Module List\r
1697 #\r
1698 ModuleList = {}\r
1699 for Pa in Wa.AutoGenObjectList:\r
1700 for Ma in Pa.ModuleAutoGenList:\r
1701 if Ma == None:\r
1702 continue\r
1703 if not Ma.IsLibrary:\r
1704 ModuleList[Ma.Guid.upper()] = Ma\r
1705 #\r
1706 # Rebase module to the preferred memory address before GenFds\r
1707 #\r
1708 MapBuffer = StringIO('')\r
1709 if self.LoadFixAddress != 0:\r
1710 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1711\r
1712 if self.Fdf:\r
1713 #\r
1714 # Generate FD image if there's a FDF file found\r
1715 #\r
1716 LaunchCommand(Wa.GenFdsCommand, os.getcwd())\r
1717\r
1718 #\r
1719 # Create MAP file for all platform FVs after GenFds.\r
1720 #\r
1721 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1722 #\r
1723 # Save MAP buffer into MAP file.\r
1724 #\r
1725 self._SaveMapFile(MapBuffer, Wa)\r
1726\r
1727 ## Generate GuidedSectionTools.txt in the FV directories.\r
1728 #\r
1729 def CreateGuidedSectionToolsFile(self):\r
1730 for BuildTarget in self.BuildTargetList:\r
1731 for ToolChain in self.ToolChainList:\r
1732 Wa = WorkspaceAutoGen(\r
1733 self.WorkspaceDir,\r
1734 self.PlatformFile,\r
1735 BuildTarget,\r
1736 ToolChain,\r
1737 self.ArchList,\r
1738 self.BuildDatabase,\r
1739 self.TargetTxt,\r
1740 self.ToolDef,\r
1741 self.Fdf,\r
1742 self.FdList,\r
1743 self.FvList,\r
1744 self.CapList,\r
1745 self.SkuId,\r
1746 self.UniFlag\r
1747 )\r
1748 FvDir = Wa.FvDir\r
1749 if not os.path.exists(FvDir):\r
1750 continue\r
1751\r
1752 for Arch in self.ArchList:\r
1753 # Build up the list of supported architectures for this build\r
1754 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
1755\r
1756 # Look through the tool definitions for GUIDed tools\r
1757 guidAttribs = []\r
1758 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
1759 if attrib.upper().endswith('_GUID'):\r
1760 split = attrib.split('_')\r
1761 thisPrefix = '_'.join(split[0:3]) + '_'\r
1762 if thisPrefix == prefix:\r
1763 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
1764 guid = guid.lower()\r
1765 toolName = split[3]\r
1766 path = '_'.join(split[0:4]) + '_PATH'\r
1767 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
1768 path = self.GetFullPathOfTool(path)\r
1769 guidAttribs.append((guid, toolName, path))\r
1770\r
1771 # Write out GuidedSecTools.txt\r
1772 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
1773 toolsFile = open(toolsFile, 'wt')\r
1774 for guidedSectionTool in guidAttribs:\r
1775 print >> toolsFile, ' '.join(guidedSectionTool)\r
1776 toolsFile.close()\r
1777\r
1778 ## Returns the full path of the tool.\r
1779 #\r
1780 def GetFullPathOfTool (self, tool):\r
1781 if os.path.exists(tool):\r
1782 return os.path.realpath(tool)\r
1783 else:\r
1784 # We need to search for the tool using the\r
1785 # PATH environment variable.\r
1786 for dirInPath in os.environ['PATH'].split(os.pathsep):\r
1787 foundPath = os.path.join(dirInPath, tool)\r
1788 if os.path.exists(foundPath):\r
1789 return os.path.realpath(foundPath)\r
1790\r
1791 # If the tool was not found in the path then we just return\r
1792 # the input tool.\r
1793 return tool\r
1794\r
1795 ## Launch the module or platform build\r
1796 #\r
1797 def Launch(self):\r
1798 if not self.ModuleFile:\r
1799 if not self.SpawnMode or self.Target not in ["", "all"]:\r
1800 self.SpawnMode = False\r
1801 self._BuildPlatform()\r
1802 else:\r
1803 self._MultiThreadBuildPlatform()\r
1804 self.CreateGuidedSectionToolsFile()\r
1805 else:\r
1806 self.SpawnMode = False\r
1807 self._BuildModule()\r
1808\r
1809 if self.Target == 'cleanall':\r
1810 self.Db.Close()\r
1811 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)\r
1812\r
1813 def CreateAsBuiltInf(self):\r
1814 for Module in self.BuildModules:\r
1815 Module.CreateAsBuiltInf()\r
1816 self.BuildModules = []\r
1817 ## Do some clean-up works when error occurred\r
1818 def Relinquish(self):\r
1819 OldLogLevel = EdkLogger.GetLevel()\r
1820 EdkLogger.SetLevel(EdkLogger.ERROR)\r
1821 #self.DumpBuildData()\r
1822 Utils.Progressor.Abort()\r
1823 if self.SpawnMode == True:\r
1824 BuildTask.Abort()\r
1825 EdkLogger.SetLevel(OldLogLevel)\r
1826\r
1827 def DumpBuildData(self):\r
1828 CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)\r
1829 Utils.CreateDirectory(CacheDirectory)\r
1830 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
1831 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
1832\r
1833 def RestoreBuildData(self):\r
1834 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")\r
1835 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
1836 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
1837 if Utils.gFileTimeStampCache == None:\r
1838 Utils.gFileTimeStampCache = {}\r
1839\r
1840 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")\r
1841 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
1842 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
1843 if Utils.gDependencyDatabase == None:\r
1844 Utils.gDependencyDatabase = {}\r
1845\r
1846def ParseDefines(DefineList=[]):\r
1847 DefineDict = {}\r
1848 if DefineList != None:\r
1849 for Define in DefineList:\r
1850 DefineTokenList = Define.split("=", 1)\r
1851 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):\r
1852 EdkLogger.error('build', FORMAT_INVALID,\r
1853 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",\r
1854 ExtraData=DefineTokenList[0])\r
1855\r
1856 if len(DefineTokenList) == 1:\r
1857 DefineDict[DefineTokenList[0]] = "TRUE"\r
1858 else:\r
1859 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
1860 return DefineDict\r
1861\r
1862gParamCheck = []\r
1863def SingleCheckCallback(option, opt_str, value, parser):\r
1864 if option not in gParamCheck:\r
1865 setattr(parser.values, option.dest, value)\r
1866 gParamCheck.append(option)\r
1867 else:\r
1868 parser.error("Option %s only allows one instance in command line!" % option)\r
1869\r
1870## Parse command line options\r
1871#\r
1872# Using standard Python module optparse to parse command line option of this tool.\r
1873#\r
1874# @retval Opt A optparse.Values object containing the parsed options\r
1875# @retval Args Target of build command\r
1876#\r
1877def MyOptionParser():\r
1878 Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")\r
1879 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch",\r
1880 help="ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")\r
1881 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
1882 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
1883 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
1884 help="Build the module specified by the INF file name argument.")\r
1885 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",\r
1886 action="append")\r
1887 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
1888 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
1889 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
1890 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
1891\r
1892 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
1893 help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. Less than 2 will disable multi-thread builds.")\r
1894\r
1895 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
1896 help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
1897 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
1898 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
1899 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
1900 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
1901 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],\r
1902 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")\r
1903 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
1904 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
1905\r
1906 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")\r
1907\r
1908 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
1909 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
1910\r
1911 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
1912 help="Make use of silent mode of (n)make.")\r
1913 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
1914 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
1915 "including library instances selected, final dependency expression, "\\r
1916 "and warning messages, etc.")\r
1917 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
1918 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
1919\r
1920 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
1921 Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'EXECUTION_ORDER'], dest="ReportType", default=[],\r
1922 help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, EXECUTION_ORDER]. "\\r
1923 "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS]")\r
1924 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",\r
1925 help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\\r
1926 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\\r
1927 "will override the setting in [BuildOptions] section of platform DSC.")\r
1928 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")\r
1929 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")\r
1930 Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")\r
1931 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")\r
1932\r
1933 (Opt, Args) = Parser.parse_args()\r
1934 return (Opt, Args)\r
1935\r
1936## Tool entrance method\r
1937#\r
1938# This method mainly dispatch specific methods per the command line options.\r
1939# If no error found, return zero value so the caller of this tool can know\r
1940# if it's executed successfully or not.\r
1941#\r
1942# @retval 0 Tool was successful\r
1943# @retval 1 Tool failed\r
1944#\r
1945def Main():\r
1946 StartTime = time.time()\r
1947\r
1948 # Initialize log system\r
1949 EdkLogger.Initialize()\r
1950\r
1951 #\r
1952 # Parse the options and args\r
1953 #\r
1954 (Option, Target) = MyOptionParser()\r
1955 GlobalData.gOptions = Option\r
1956 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
1957\r
1958 # Set log level\r
1959 if Option.verbose != None:\r
1960 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
1961 elif Option.quiet != None:\r
1962 EdkLogger.SetLevel(EdkLogger.QUIET)\r
1963 elif Option.debug != None:\r
1964 EdkLogger.SetLevel(Option.debug + 1)\r
1965 else:\r
1966 EdkLogger.SetLevel(EdkLogger.INFO)\r
1967\r
1968 if Option.LogFile != None:\r
1969 EdkLogger.SetLogFile(Option.LogFile)\r
1970\r
1971 if Option.WarningAsError == True:\r
1972 EdkLogger.SetWarningAsError()\r
1973\r
1974 if platform.platform().find("Windows") >= 0:\r
1975 GlobalData.gIsWindows = True\r
1976 else:\r
1977 GlobalData.gIsWindows = False\r
1978\r
1979 EdkLogger.quiet("Build environment: %s" % platform.platform())\r
1980 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));\r
1981 ReturnCode = 0\r
1982 MyBuild = None\r
1983 BuildError = True\r
1984 try:\r
1985 if len(Target) == 0:\r
1986 Target = "all"\r
1987 elif len(Target) >= 2:\r
1988 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
1989 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
1990 else:\r
1991 Target = Target[0].lower()\r
1992\r
1993 if Target not in gSupportedTarget:\r
1994 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
1995 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
1996\r
1997 #\r
1998 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
1999 #\r
2000 CheckEnvVariable()\r
2001 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))\r
2002\r
2003 Workspace = os.getenv("WORKSPACE")\r
2004 #\r
2005 # Get files real name in workspace dir\r
2006 #\r
2007 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
2008\r
2009 WorkingDirectory = os.getcwd()\r
2010 if not Option.ModuleFile:\r
2011 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
2012 FileNum = len(FileList)\r
2013 if FileNum >= 2:\r
2014 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
2015 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
2016 elif FileNum == 1:\r
2017 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
2018\r
2019 if Option.ModuleFile:\r
2020 if os.path.isabs (Option.ModuleFile):\r
2021 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
2022 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
2023 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
2024 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
2025 if ErrorCode != 0:\r
2026 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2027\r
2028 if Option.PlatformFile != None:\r
2029 if os.path.isabs (Option.PlatformFile):\r
2030 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
2031 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
2032 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
2033\r
2034 if Option.FdfFile != None:\r
2035 if os.path.isabs (Option.FdfFile):\r
2036 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
2037 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
2038 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
2039 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
2040 if ErrorCode != 0:\r
2041 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2042\r
2043 if Option.Flag != None and Option.Flag not in ['-c', '-s']:\r
2044 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
2045\r
2046 MyBuild = Build(Target, Workspace, Option)\r
2047 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)\r
2048 MyBuild.Launch()\r
2049 # Drop temp tables to avoid database locked.\r
2050 for TmpTableName in TmpTableDict:\r
2051 SqlCommand = """drop table IF EXISTS %s""" % TmpTableName\r
2052 TmpTableDict[TmpTableName].execute(SqlCommand)\r
2053 #MyBuild.DumpBuildData()\r
2054 #\r
2055 # All job done, no error found and no exception raised\r
2056 #\r
2057 BuildError = False\r
2058 except FatalError, X:\r
2059 if MyBuild != None:\r
2060 # for multi-thread build exits safely\r
2061 MyBuild.Relinquish()\r
2062 if Option != None and Option.debug != None:\r
2063 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2064 ReturnCode = X.args[0]\r
2065 except Warning, X:\r
2066 # error from Fdf parser\r
2067 if MyBuild != None:\r
2068 # for multi-thread build exits safely\r
2069 MyBuild.Relinquish()\r
2070 if Option != None and Option.debug != None:\r
2071 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2072 else:\r
2073 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
2074 ReturnCode = FORMAT_INVALID\r
2075 except KeyboardInterrupt:\r
2076 ReturnCode = ABORT_ERROR\r
2077 if Option != None and Option.debug != None:\r
2078 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2079 except:\r
2080 if MyBuild != None:\r
2081 # for multi-thread build exits safely\r
2082 MyBuild.Relinquish()\r
2083\r
2084 # try to get the meta-file from the object causing exception\r
2085 Tb = sys.exc_info()[-1]\r
2086 MetaFile = GlobalData.gProcessingFile\r
2087 while Tb != None:\r
2088 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
2089 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
2090 Tb = Tb.tb_next\r
2091 EdkLogger.error(\r
2092 "\nbuild",\r
2093 CODE_ERROR,\r
2094 "Unknown fatal error when processing [%s]" % MetaFile,\r
2095 ExtraData="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",\r
2096 RaiseError=False\r
2097 )\r
2098 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2099 ReturnCode = CODE_ERROR\r
2100 finally:\r
2101 Utils.Progressor.Abort()\r
2102 Utils.ClearDuplicatedInf()\r
2103\r
2104 if ReturnCode == 0:\r
2105 Conclusion = "Done"\r
2106 elif ReturnCode == ABORT_ERROR:\r
2107 Conclusion = "Aborted"\r
2108 else:\r
2109 Conclusion = "Failed"\r
2110 FinishTime = time.time()\r
2111 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))\r
2112 BuildDurationStr = ""\r
2113 if BuildDuration.tm_yday > 1:\r
2114 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)\r
2115 else:\r
2116 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)\r
2117 if MyBuild != None:\r
2118 if not BuildError:\r
2119 MyBuild.BuildReport.GenerateReport(BuildDurationStr)\r
2120 MyBuild.Db.Close()\r
2121 EdkLogger.SetLevel(EdkLogger.QUIET)\r
2122 EdkLogger.quiet("\n- %s -" % Conclusion)\r
2123 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
2124 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
2125 return ReturnCode\r
2126\r
2127if __name__ == '__main__':\r
2128 r = Main()\r
2129 ## 0-127 is a safe return range, and 1 is a standard default error\r
2130 if r < 0 or r > 127: r = 1\r
2131 sys.exit(r)\r
2132\r