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