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