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