]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/build.py
The patch enhances the Partition driver to return the media status (EFI_NO_MEDIA...
[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
915 FdfParserObj = FdfParser(str(self.Fdf))\r
da92f276
LG
916 for key in self.Db._GlobalMacros:\r
917 InputMacroDict[key] = self.Db._GlobalMacros[key]\r
52302d4d
LG
918 FdfParserObj.ParseFile()\r
919 for fvname in self.FvList:\r
920 if fvname.upper() not in FdfParserObj.Profile.FvDict.keys():\r
921 EdkLogger.error("build", OPTION_VALUE_INVALID,\r
922 "No such an FV in FDF file: %s" % fvname)\r
923\r
924 #\r
925 # Merge Arch\r
926 #\r
927 if self.ArchList == None or len(self.ArchList) == 0:\r
928 ArchList = set(self.Platform.SupArchList)\r
929 else:\r
930 ArchList = set(self.ArchList) & set(self.Platform.SupArchList)\r
931 if len(ArchList) == 0:\r
932 EdkLogger.error("build", PARAMETER_INVALID,\r
933 ExtraData = "Active platform supports [%s] only, but [%s] is given."\r
934 % (" ".join(self.Platform.SupArchList), " ".join(self.ArchList)))\r
935 elif len(ArchList) != len(self.ArchList):\r
936 SkippedArchList = set(self.ArchList).symmetric_difference(set(self.Platform.SupArchList))\r
937 EdkLogger.verbose("\nArch [%s] is ignored because active platform supports [%s] but [%s] is specified !"\r
938 % (" ".join(SkippedArchList), " ".join(self.Platform.SupArchList), " ".join(self.ArchList)))\r
939 self.ArchList = tuple(ArchList)\r
940\r
941 # Merge build target\r
942 if self.BuildTargetList == None or len(self.BuildTargetList) == 0:\r
943 BuildTargetList = self.Platform.BuildTargets\r
944 else:\r
945 BuildTargetList = list(set(self.BuildTargetList) & set(self.Platform.BuildTargets))\r
946 if BuildTargetList == []:\r
947 EdkLogger.error("build", PARAMETER_INVALID, "Active platform only supports [%s], but [%s] is given"\r
948 % (" ".join(self.Platform.BuildTargets), " ".join(self.BuildTargetList)))\r
949 self.BuildTargetList = BuildTargetList\r
950\r
951 ## Build a module or platform\r
952 #\r
08dd311f 953 # Create autogen code and makefile for a module or platform, and the launch\r
52302d4d
LG
954 # "make" command to build it\r
955 #\r
956 # @param Target The target of build command\r
957 # @param Platform The platform file\r
958 # @param Module The module file\r
959 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
960 # @param ToolChain The name of toolchain to build\r
961 # @param Arch The arch of the module/platform\r
962 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
963 # for dependent modules/Libraries\r
964 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
965 # for dependent modules/Libraries\r
966 #\r
967 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True):\r
968 if AutoGenObject == None:\r
969 return False\r
970\r
971 # skip file generation for cleanxxx targets, run and fds target\r
972 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
973 # for target which must generate AutoGen code and makefile\r
974 if not self.SkipAutoGen or Target == 'genc':\r
975 self.Progress.Start("Generating code")\r
976 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
977 self.Progress.Stop("done!")\r
978 if Target == "genc":\r
979 return True\r
980\r
981 if not self.SkipAutoGen or Target == 'genmake':\r
982 self.Progress.Start("Generating makefile")\r
983 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
da92f276 984 AutoGenObject.CreateAsBuiltInf()\r
52302d4d
LG
985 self.Progress.Stop("done!")\r
986 if Target == "genmake":\r
987 return True\r
988 else:\r
989 # always recreate top/platform makefile when clean, just in case of inconsistency\r
990 AutoGenObject.CreateCodeFile(False)\r
991 AutoGenObject.CreateMakeFile(False)\r
992\r
993 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
994 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
995\r
996 BuildCommand = AutoGenObject.BuildCommand\r
997 if BuildCommand == None or len(BuildCommand) == 0:\r
998 EdkLogger.error("build", OPTION_MISSING, ExtraData="No MAKE command found for [%s, %s, %s]" % Key)\r
999\r
1000 BuildCommand = BuildCommand + [Target]\r
1001 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
1002 if Target == 'cleanall':\r
1003 try:\r
1004 #os.rmdir(AutoGenObject.BuildDir)\r
1005 RemoveDirectory(AutoGenObject.BuildDir, True)\r
4234283c
LG
1006 #\r
1007 # First should close DB.\r
1008 #\r
1009 self.Db.Close() \r
1010 RemoveDirectory(gBuildCacheDir, True)\r
52302d4d
LG
1011 except WindowsError, X:\r
1012 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1013 return True\r
1014\r
6780eef1 1015 ## Rebase module image and Get function address for the input module list.\r
52302d4d
LG
1016 #\r
1017 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
1018 if ModeIsSmm:\r
1019 AddrIsOffset = False\r
1020 InfFileNameList = ModuleList.keys()\r
1021 #InfFileNameList.sort()\r
1022 for InfFile in InfFileNameList:\r
da92f276
LG
1023 sys.stdout.write (".")\r
1024 sys.stdout.flush()\r
52302d4d
LG
1025 ModuleInfo = ModuleList[InfFile]\r
1026 ModuleName = ModuleInfo.BaseName\r
f3decdc3
LG
1027 ModuleOutputImage = ModuleInfo.Image.FileName\r
1028 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')\r
52302d4d
LG
1029 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1030 if not ModeIsSmm:\r
1031 BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
1032 #\r
1033 # Update Image to new BaseAddress by GenFw tool\r
1034 #\r
f3decdc3
LG
1035 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
1036 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1037 else:\r
1038 #\r
1039 # Set new address to the section header only for SMM driver.\r
1040 #\r
f3decdc3
LG
1041 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
1042 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1043 #\r
1044 # Collect funtion address from Map file\r
1045 #\r
f3decdc3 1046 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')\r
52302d4d
LG
1047 FunctionList = []\r
1048 if os.path.exists(ImageMapTable):\r
1049 OrigImageBaseAddress = 0\r
1050 ImageMap = open (ImageMapTable, 'r')\r
1051 for LinStr in ImageMap:\r
1052 if len (LinStr.strip()) == 0:\r
1053 continue\r
1054 #\r
1055 # Get the preferred address set on link time.\r
1056 #\r
1057 if LinStr.find ('Preferred load address is') != -1:\r
1058 StrList = LinStr.split()\r
1059 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
1060\r
1061 StrList = LinStr.split()\r
1062 if len (StrList) > 4:\r
1063 if StrList[3] == 'f' or StrList[3] =='F':\r
1064 Name = StrList[1]\r
1065 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
1066 FunctionList.append ((Name, RelativeAddress))\r
1067 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):\r
1068 #\r
1069 # Get the real entry point address for IPF image.\r
1070 #\r
1071 ModuleInfo.Image.EntryPoint = RelativeAddress\r
1072 ImageMap.close()\r
1073 #\r
1074 # Add general information.\r
1075 #\r
1076 if ModeIsSmm:\r
1077 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1078 elif AddrIsOffset:\r
1079 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
1080 else:\r
1081 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1082 #\r
1083 # Add guid and general seciton section.\r
1084 #\r
1085 TextSectionAddress = 0\r
1086 DataSectionAddress = 0\r
1087 for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
1088 if SectionHeader[0] == '.text':\r
1089 TextSectionAddress = SectionHeader[1]\r
1090 elif SectionHeader[0] in ['.data', '.sdata']:\r
1091 DataSectionAddress = SectionHeader[1]\r
1092 if AddrIsOffset:\r
f3decdc3 1093 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress))) \r
52302d4d 1094 else:\r
f3decdc3
LG
1095 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress)) \r
1096 #\r
1097 # Add debug image full path.\r
1098 #\r
1099 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
52302d4d
LG
1100 #\r
1101 # Add funtion address\r
1102 #\r
1103 for Function in FunctionList:\r
1104 if AddrIsOffset:\r
1105 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
1106 else:\r
1107 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))\r
1108 ImageMap.close()\r
1109\r
1110 #\r
1111 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1112 #\r
1113 if ModeIsSmm:\r
1114 BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
1115\r
1116 ## Collect MAP information of all FVs\r
1117 #\r
636f2be6 1118 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):\r
52302d4d
LG
1119 if self.Fdf != '':\r
1120 # First get the XIP base address for FV map file.\r
636f2be6 1121 GuidPattern = re.compile("[-a-fA-F0-9]+")\r
f3decdc3 1122 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")\r
52302d4d
LG
1123 for FvName in Wa.FdfProfile.FvDict.keys():\r
1124 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
1125 if not os.path.exists(FvMapBuffer):\r
1126 continue\r
1127 FvMap = open (FvMapBuffer, 'r')\r
1128 #skip FV size information\r
1129 FvMap.readline()\r
1130 FvMap.readline()\r
1131 FvMap.readline()\r
1132 FvMap.readline()\r
636f2be6
LG
1133 for Line in FvMap:\r
1134 MatchGuid = GuidPattern.match(Line)\r
1135 if MatchGuid != None:\r
1136 #\r
1137 # Replace GUID with module name\r
1138 #\r
1139 GuidString = MatchGuid.group()\r
1140 if GuidString.upper() in ModuleList:\r
1141 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
1142 MapBuffer.write('%s' % (Line))\r
f3decdc3
LG
1143 #\r
1144 # Add the debug image full path.\r
1145 #\r
1146 MatchGuid = GuidName.match(Line)\r
1147 if MatchGuid != None:\r
1148 GuidString = MatchGuid.group().split("=")[1]\r
1149 if GuidString.upper() in ModuleList:\r
1150 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
1151\r
52302d4d
LG
1152 FvMap.close()\r
1153\r
1154 ## Collect MAP information of all modules\r
1155 #\r
1156 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
da92f276
LG
1157 sys.stdout.write ("Generate Load Module At Fix Address Map")\r
1158 sys.stdout.flush()\r
52302d4d
LG
1159 PatchEfiImageList = []\r
1160 PeiModuleList = {}\r
1161 BtModuleList = {}\r
1162 RtModuleList = {}\r
1163 SmmModuleList = {}\r
1164 PeiSize = 0\r
1165 BtSize = 0\r
1166 RtSize = 0\r
1167 # reserve 4K size in SMRAM to make SMM module address not from 0.\r
1168 SmmSize = 0x1000\r
1169 IsIpfPlatform = False\r
1170 if 'IPF' in self.ArchList:\r
1171 IsIpfPlatform = True\r
636f2be6
LG
1172 for ModuleGuid in ModuleList:\r
1173 Module = ModuleList[ModuleGuid]\r
52302d4d
LG
1174 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
1175 \r
1176 OutputImageFile = ''\r
1177 for ResultFile in Module.CodaTargetList:\r
1178 if str(ResultFile.Target).endswith('.efi'):\r
1179 #\r
1180 # module list for PEI, DXE, RUNTIME and SMM\r
1181 #\r
1182 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
1183 ImageClass = PeImageClass (OutputImageFile)\r
1184 if not ImageClass.IsValid:\r
1185 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
f3decdc3 1186 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)\r
52302d4d
LG
1187 if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER','PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:\r
1188 PeiModuleList[Module.MetaFile] = ImageInfo\r
1189 PeiSize += ImageInfo.Image.Size\r
1190 elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:\r
1191 BtModuleList[Module.MetaFile] = ImageInfo\r
1192 BtSize += ImageInfo.Image.Size\r
1193 elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:\r
1194 RtModuleList[Module.MetaFile] = ImageInfo\r
1195 #IPF runtime driver needs to be at 2 page alignment.\r
1196 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:\r
1197 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000\r
1198 RtSize += ImageInfo.Image.Size\r
1199 elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:\r
1200 SmmModuleList[Module.MetaFile] = ImageInfo\r
1201 SmmSize += ImageInfo.Image.Size\r
1202 if Module.ModuleType == 'DXE_SMM_DRIVER':\r
da92f276
LG
1203 PiSpecVersion = '0x00000000'\r
1204 if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:\r
1205 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']\r
52302d4d 1206 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
da92f276 1207 if int(PiSpecVersion, 16) < 0x0001000A:\r
52302d4d
LG
1208 BtModuleList[Module.MetaFile] = ImageInfo\r
1209 BtSize += ImageInfo.Image.Size\r
1210 break\r
1211 #\r
1212 # EFI image is final target.\r
1213 # Check EFI image contains patchable FixAddress related PCDs.\r
1214 #\r
1215 if OutputImageFile != '':\r
1216 ModuleIsPatch = False\r
1217 for Pcd in Module.ModulePcdList:\r
1218 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1219 ModuleIsPatch = True\r
1220 break\r
1221 if not ModuleIsPatch:\r
1222 for Pcd in Module.LibraryPcdList:\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 \r
1227 if not ModuleIsPatch:\r
1228 continue\r
1229 #\r
1230 # Module includes the patchable load fix address PCDs.\r
1231 # It will be fixed up later. \r
1232 #\r
1233 PatchEfiImageList.append (OutputImageFile)\r
1234 \r
1235 #\r
1236 # Get Top Memory address\r
1237 #\r
1238 ReservedRuntimeMemorySize = 0\r
1239 TopMemoryAddress = 0\r
1240 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
1241 TopMemoryAddress = 0\r
1242 else:\r
1243 TopMemoryAddress = self.LoadFixAddress\r
1244 if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
1245 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
1246 # Make IPF runtime driver at 2 page alignment.\r
1247 if IsIpfPlatform:\r
1248 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000\r
1249 RtSize = RtSize + ReservedRuntimeMemorySize\r
1250\r
1251 #\r
1252 # Patch FixAddress related PCDs into EFI image\r
1253 #\r
1254 for EfiImage in PatchEfiImageList: \r
1255 EfiImageMap = EfiImage.replace('.efi', '.map')\r
1256 if not os.path.exists(EfiImageMap):\r
1257 continue\r
1258 #\r
1259 # Get PCD offset in EFI image by GenPatchPcdTable function\r
1260 #\r
da92f276 1261 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage) \r
52302d4d
LG
1262 #\r
1263 # Patch real PCD value by PatchPcdValue tool\r
1264 #\r
1265 for PcdInfo in PcdTable:\r
1266 ReturnValue = 0\r
1267 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
1268 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize/0x1000))\r
1269 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
1270 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize/0x1000))\r
1271 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
1272 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize/0x1000))\r
1273 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
1274 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize/0x1000))\r
1275 if ReturnValue != 0:\r
1276 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
1277 \r
1278 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize/0x1000))\r
1279 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize/0x1000))\r
1280 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize/0x1000))\r
1281 if len (SmmModuleList) > 0:\r
1282 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize/0x1000))\r
1283 \r
e56468c0 1284 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize \r
52302d4d 1285 BtBaseAddr = TopMemoryAddress - RtSize\r
e56468c0 1286 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize \r
52302d4d
LG
1287\r
1288 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
1289 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
1290 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
1291 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset = False, ModeIsSmm = True)\r
1292 MapBuffer.write('\n\n')\r
da92f276
LG
1293 sys.stdout.write ("\n")\r
1294 sys.stdout.flush()\r
52302d4d
LG
1295 \r
1296 ## Save platform Map file\r
1297 #\r
1298 def _SaveMapFile (self, MapBuffer, Wa):\r
1299 #\r
1300 # Map file path is got.\r
1301 #\r
1302 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
1303 #\r
1304 # Save address map into MAP file.\r
1305 #\r
40d841f6 1306 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
da92f276
LG
1307 MapBuffer.close()\r
1308 if self.LoadFixAddress != 0:\r
1309 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" %(MapFilePath))\r
1310 sys.stdout.flush()\r
52302d4d
LG
1311\r
1312 ## Build active platform for different build targets and different tool chains\r
1313 #\r
1314 def _BuildPlatform(self):\r
1315 for BuildTarget in self.BuildTargetList:\r
1316 for ToolChain in self.ToolChainList:\r
1317 Wa = WorkspaceAutoGen(\r
1318 self.WorkspaceDir,\r
1319 self.Platform,\r
1320 BuildTarget,\r
1321 ToolChain,\r
1322 self.ArchList,\r
1323 self.BuildDatabase,\r
1324 self.TargetTxt,\r
1325 self.ToolDef,\r
1326 self.Fdf,\r
1327 self.FdList,\r
1328 self.FvList,\r
4234283c 1329 self.CapList,\r
f3decdc3
LG
1330 self.SkuId,\r
1331 self.UniFlag\r
52302d4d
LG
1332 )\r
1333 self.BuildReport.AddPlatformReport(Wa)\r
1334 self.Progress.Stop("done!")\r
1335 self._Build(self.Target, Wa)\r
1336 \r
1337 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1338 if self.Target in ["", "all", "fds"]:\r
52302d4d
LG
1339 for Arch in self.ArchList:\r
1340 #\r
1341 # Check whether the set fix address is above 4G for 32bit image.\r
1342 #\r
1343 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1344 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
1345 #\r
1346 # Get Module List\r
1347 #\r
636f2be6 1348 ModuleList = {}\r
52302d4d
LG
1349 for Pa in Wa.AutoGenObjectList:\r
1350 for Ma in Pa.ModuleAutoGenList:\r
1351 if Ma == None:\r
1352 continue\r
1353 if not Ma.IsLibrary:\r
636f2be6 1354 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1355\r
1356 MapBuffer = StringIO('')\r
636f2be6
LG
1357 if self.LoadFixAddress != 0:\r
1358 #\r
1359 # Rebase module to the preferred memory address before GenFds\r
1360 #\r
1361 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
f3decdc3
LG
1362 if self.Fdf != '':\r
1363 #\r
1364 # create FDS again for the updated EFI image\r
1365 #\r
1366 self._Build("fds", Wa)\r
52302d4d 1367 if self.Fdf != '':\r
52302d4d
LG
1368 #\r
1369 # Create MAP file for all platform FVs after GenFds.\r
1370 #\r
636f2be6 1371 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1372 #\r
1373 # Save MAP buffer into MAP file.\r
1374 #\r
1375 self._SaveMapFile (MapBuffer, Wa)\r
1376\r
1377 ## Build active module for different build targets, different tool chains and different archs\r
1378 #\r
1379 def _BuildModule(self):\r
1380 for BuildTarget in self.BuildTargetList:\r
1381 for ToolChain in self.ToolChainList:\r
1382 #\r
1383 # module build needs platform build information, so get platform\r
1384 # AutoGen first\r
1385 #\r
1386 Wa = WorkspaceAutoGen(\r
1387 self.WorkspaceDir,\r
1388 self.Platform,\r
1389 BuildTarget,\r
1390 ToolChain,\r
1391 self.ArchList,\r
1392 self.BuildDatabase,\r
1393 self.TargetTxt,\r
1394 self.ToolDef,\r
1395 self.Fdf,\r
1396 self.FdList,\r
1397 self.FvList,\r
4234283c 1398 self.CapList,\r
f3decdc3
LG
1399 self.SkuId,\r
1400 self.UniFlag\r
52302d4d 1401 )\r
52302d4d
LG
1402 Wa.CreateMakeFile(False)\r
1403 self.Progress.Stop("done!")\r
1404 MaList = []\r
1405 for Arch in self.ArchList:\r
1406 Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1407 if Ma == None: continue\r
1408 MaList.append(Ma)\r
1409 self._Build(self.Target, Ma)\r
d5d56f1b
LG
1410\r
1411 self.BuildReport.AddPlatformReport(Wa, MaList)\r
52302d4d
LG
1412 if MaList == []:\r
1413 EdkLogger.error(\r
1414 'build',\r
1415 BUILD_ERROR,\r
1416 "Module for [%s] is not a component of active platform."\\r
1417 " Please make sure that the ARCH and inf file path are"\\r
1418 " given in the same as in [%s]" %\\r
1419 (', '.join(self.ArchList), self.Platform),\r
1420 ExtraData=self.ModuleFile\r
1421 )\r
1422 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1423 if self.Target == "fds" and self.Fdf != '':\r
52302d4d
LG
1424 for Arch in self.ArchList:\r
1425 #\r
1426 # Check whether the set fix address is above 4G for 32bit image.\r
1427 #\r
1428 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1429 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
1430 #\r
1431 # Get Module List\r
1432 #\r
636f2be6 1433 ModuleList = {}\r
52302d4d
LG
1434 for Pa in Wa.AutoGenObjectList:\r
1435 for Ma in Pa.ModuleAutoGenList:\r
1436 if Ma == None:\r
1437 continue\r
1438 if not Ma.IsLibrary:\r
636f2be6 1439 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1440\r
1441 MapBuffer = StringIO('')\r
636f2be6
LG
1442 if self.LoadFixAddress != 0:\r
1443 #\r
1444 # Rebase module to the preferred memory address before GenFds\r
1445 #\r
1446 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1447 #\r
1448 # create FDS again for the updated EFI image\r
1449 #\r
1450 self._Build("fds", Wa)\r
52302d4d
LG
1451 #\r
1452 # Create MAP file for all platform FVs after GenFds.\r
1453 #\r
636f2be6 1454 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1455 #\r
1456 # Save MAP buffer into MAP file.\r
1457 #\r
1458 self._SaveMapFile (MapBuffer, Wa)\r
1459\r
1460 ## Build a platform in multi-thread mode\r
1461 #\r
1462 def _MultiThreadBuildPlatform(self):\r
1463 for BuildTarget in self.BuildTargetList:\r
1464 for ToolChain in self.ToolChainList:\r
1465 Wa = WorkspaceAutoGen(\r
1466 self.WorkspaceDir,\r
1467 self.Platform,\r
1468 BuildTarget,\r
1469 ToolChain,\r
1470 self.ArchList,\r
1471 self.BuildDatabase,\r
1472 self.TargetTxt,\r
1473 self.ToolDef,\r
1474 self.Fdf,\r
1475 self.FdList,\r
1476 self.FvList,\r
4234283c 1477 self.CapList,\r
f3decdc3
LG
1478 self.SkuId,\r
1479 self.UniFlag\r
52302d4d
LG
1480 )\r
1481 self.BuildReport.AddPlatformReport(Wa)\r
1482 Wa.CreateMakeFile(False)\r
1483\r
1484 # multi-thread exit flag\r
1485 ExitFlag = threading.Event()\r
1486 ExitFlag.clear()\r
1487 for Arch in self.ArchList:\r
1488 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1489 if Pa == None:\r
1490 continue\r
1491 for Module in Pa.Platform.Modules:\r
1492 # Get ModuleAutoGen object to generate C code file and makefile\r
1493 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1494 if Ma == None:\r
1495 continue\r
1496 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1497 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1498 # for target which must generate AutoGen code and makefile\r
1499 if not self.SkipAutoGen or self.Target == 'genc':\r
1500 Ma.CreateCodeFile(True)\r
1501 if self.Target == "genc":\r
1502 continue\r
1503\r
1504 if not self.SkipAutoGen or self.Target == 'genmake':\r
1505 Ma.CreateMakeFile(True)\r
da92f276 1506 Ma.CreateAsBuiltInf()\r
52302d4d
LG
1507 if self.Target == "genmake":\r
1508 continue\r
1509 self.Progress.Stop("done!")\r
1510 # Generate build task for the module\r
1511 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
1512 # Break build if any build thread has error\r
1513 if BuildTask.HasError():\r
1514 # we need a full version of makefile for platform\r
1515 ExitFlag.set()\r
1516 BuildTask.WaitForComplete()\r
1517 Pa.CreateMakeFile(False)\r
1518 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1519 # Start task scheduler\r
1520 if not BuildTask.IsOnGoing():\r
1521 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1522\r
1523 # in case there's an interruption. we need a full version of makefile for platform\r
1524 Pa.CreateMakeFile(False)\r
1525 if BuildTask.HasError():\r
1526 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1527\r
1528 #\r
1529 # All modules have been put in build tasks queue. Tell task scheduler\r
1530 # to exit if all tasks are completed\r
1531 #\r
1532 ExitFlag.set()\r
1533 BuildTask.WaitForComplete()\r
1534\r
1535 #\r
1536 # Check for build error, and raise exception if one\r
1537 # has been signaled.\r
1538 #\r
1539 if BuildTask.HasError():\r
1540 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1541\r
1542 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1543 if self.Target in ["", "all", "fds"]:\r
52302d4d
LG
1544 for Arch in self.ArchList:\r
1545 #\r
1546 # Check whether the set fix address is above 4G for 32bit image.\r
1547 #\r
1548 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1549 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
1550 #\r
1551 # Get Module List\r
1552 #\r
636f2be6 1553 ModuleList = {}\r
52302d4d
LG
1554 for Pa in Wa.AutoGenObjectList:\r
1555 for Ma in Pa.ModuleAutoGenList:\r
1556 if Ma == None:\r
1557 continue\r
1558 if not Ma.IsLibrary:\r
636f2be6 1559 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1560 #\r
1561 # Rebase module to the preferred memory address before GenFds\r
1562 #\r
1563 MapBuffer = StringIO('')\r
636f2be6
LG
1564 if self.LoadFixAddress != 0:\r
1565 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d 1566\r
52302d4d 1567 if self.Fdf != '':\r
f3decdc3
LG
1568 #\r
1569 # Generate FD image if there's a FDF file found\r
1570 #\r
1571 LaunchCommand(Wa.BuildCommand + ["fds"], Wa.MakeFileDir)\r
52302d4d
LG
1572 #\r
1573 # Create MAP file for all platform FVs after GenFds.\r
1574 #\r
636f2be6 1575 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1576 #\r
1577 # Save MAP buffer into MAP file.\r
1578 #\r
1579 self._SaveMapFile(MapBuffer, Wa)\r
1580\r
1581 ## Generate GuidedSectionTools.txt in the FV directories.\r
1582 #\r
1583 def CreateGuidedSectionToolsFile(self):\r
1584 for Arch in self.ArchList:\r
1585 for BuildTarget in self.BuildTargetList:\r
1586 for ToolChain in self.ToolChainList:\r
1587 FvDir = os.path.join(\r
1588 self.WorkspaceDir,\r
1589 self.Platform.OutputDirectory,\r
1590 '_'.join((BuildTarget, ToolChain)),\r
1591 'FV'\r
1592 )\r
1593 if not os.path.exists(FvDir):\r
1594 continue\r
1595 # Build up the list of supported architectures for this build\r
1596 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
1597\r
1598 # Look through the tool definitions for GUIDed tools\r
1599 guidAttribs = []\r
1600 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
1601 if attrib.upper().endswith('_GUID'):\r
1602 split = attrib.split('_')\r
1603 thisPrefix = '_'.join(split[0:3]) + '_'\r
1604 if thisPrefix == prefix:\r
1605 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
1606 guid = guid.lower()\r
1607 toolName = split[3]\r
1608 path = '_'.join(split[0:4]) + '_PATH'\r
1609 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
1610 path = self.GetFullPathOfTool(path)\r
1611 guidAttribs.append((guid, toolName, path))\r
1612\r
1613 # Write out GuidedSecTools.txt\r
1614 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
1615 toolsFile = open(toolsFile, 'wt')\r
1616 for guidedSectionTool in guidAttribs:\r
1617 print >> toolsFile, ' '.join(guidedSectionTool)\r
1618 toolsFile.close()\r
1619\r
1620 ## Returns the full path of the tool.\r
1621 #\r
1622 def GetFullPathOfTool (self, tool):\r
1623 if os.path.exists(tool):\r
1624 return os.path.realpath(tool)\r
1625 else:\r
1626 # We need to search for the tool using the\r
1627 # PATH environment variable.\r
1628 for dirInPath in os.environ['PATH'].split(os.pathsep):\r
1629 foundPath = os.path.join(dirInPath, tool)\r
1630 if os.path.exists(foundPath):\r
1631 return os.path.realpath(foundPath)\r
1632\r
1633 # If the tool was not found in the path then we just return\r
1634 # the input tool.\r
1635 return tool\r
1636\r
1637 ## Launch the module or platform build\r
1638 #\r
1639 def Launch(self):\r
1640 if self.ModuleFile == None or self.ModuleFile == "":\r
1641 if not self.SpawnMode or self.Target not in ["", "all"]:\r
1642 self.SpawnMode = False\r
1643 self._BuildPlatform()\r
1644 else:\r
1645 self._MultiThreadBuildPlatform()\r
1646 self.CreateGuidedSectionToolsFile()\r
1647 else:\r
1648 self.SpawnMode = False\r
1649 self._BuildModule()\r
1650\r
1651 ## Do some clean-up works when error occurred\r
1652 def Relinquish(self):\r
1653 OldLogLevel = EdkLogger.GetLevel()\r
1654 EdkLogger.SetLevel(EdkLogger.ERROR)\r
1655 #self.DumpBuildData()\r
1656 Utils.Progressor.Abort()\r
1657 if self.SpawnMode == True:\r
1658 BuildTask.Abort()\r
1659 EdkLogger.SetLevel(OldLogLevel)\r
1660\r
1661 def DumpBuildData(self):\r
1662 CacheDirectory = os.path.join(self.WorkspaceDir, gBuildCacheDir)\r
1663 Utils.CreateDirectory(CacheDirectory)\r
1664 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
1665 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
1666\r
1667 def RestoreBuildData(self):\r
1668 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gFileTimeStampCache")\r
1669 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
1670 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
1671 if Utils.gFileTimeStampCache == None:\r
1672 Utils.gFileTimeStampCache = {}\r
1673\r
1674 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gDependencyDatabase")\r
1675 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
1676 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
1677 if Utils.gDependencyDatabase == None:\r
1678 Utils.gDependencyDatabase = {}\r
1679\r
1680def ParseDefines(DefineList=[]):\r
1681 DefineDict = {}\r
1682 if DefineList != None:\r
1683 for Define in DefineList:\r
1684 DefineTokenList = Define.split("=", 1)\r
1685 if len(DefineTokenList) == 1:\r
1686 DefineDict[DefineTokenList[0]] = ""\r
1687 else:\r
1688 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
1689 return DefineDict\r
1690\r
1691gParamCheck = []\r
1692def SingleCheckCallback(option, opt_str, value, parser):\r
1693 if option not in gParamCheck:\r
1694 setattr(parser.values, option.dest, value)\r
1695 gParamCheck.append(option)\r
1696 else:\r
1697 parser.error("Option %s only allows one instance in command line!" % option)\r
1698\r
1699## Parse command line options\r
1700#\r
1701# Using standard Python module optparse to parse command line option of this tool.\r
1702#\r
1703# @retval Opt A optparse.Values object containing the parsed options\r
1704# @retval Args Target of build command\r
1705#\r
1706def MyOptionParser():\r
1707 Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")\r
1708 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM'], dest="TargetArch",\r
1709 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
1710 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
1711 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
1712 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
1713 help="Build the module specified by the INF file name argument.")\r
b36d134f
LG
1714 Parser.add_option("-b", "--buildtarget", action="append", type="choice", choices=['DEBUG','RELEASE','NOOPT'], dest="BuildTarget",\r
1715 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
1716 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
1717 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
1718 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
1719 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
1720\r
1721 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
1722 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
1723\r
1724 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
1725 help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
1726 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
1727 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
1728 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
1729 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
4234283c
LG
1730 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],\r
1731 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")\r
52302d4d
LG
1732 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
1733 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
1734\r
1735 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", help="Don't check case of file name.")\r
1736\r
1737 # Parser.add_option("-D", "--define", action="append", dest="Defines", metavar="NAME[=[VALUE]]",\r
1738 # help="Define global macro which can be used in DSC/DEC/INF files.")\r
1739\r
1740 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
1741 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
1742\r
1743 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
1744 help="Make use of silent mode of (n)make.")\r
1745 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
1746 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
1747 "including library instances selected, final dependency expression, "\\r
1748 "and warning messages, etc.")\r
1749 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
1750 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
1751\r
1752 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
1753 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
1754 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
1755 "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
1756 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",\r
1757 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
1758 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\\r
1759 "will override the setting in [BuildOptions] section of platform DSC.")\r
52302d4d
LG
1760\r
1761 (Opt, Args)=Parser.parse_args()\r
1762 return (Opt, Args)\r
1763\r
1764## Tool entrance method\r
1765#\r
1766# This method mainly dispatch specific methods per the command line options.\r
1767# If no error found, return zero value so the caller of this tool can know\r
1768# if it's executed successfully or not.\r
1769#\r
1770# @retval 0 Tool was successful\r
1771# @retval 1 Tool failed\r
1772#\r
1773def Main():\r
1774 StartTime = time.time()\r
1775\r
1776 # Initialize log system\r
1777 EdkLogger.Initialize()\r
1778\r
1779 #\r
1780 # Parse the options and args\r
1781 #\r
1782 (Option, Target) = MyOptionParser()\r
1783 GlobalData.gOptions = Option\r
1784 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
1785\r
1786 # Set log level\r
1787 if Option.verbose != None:\r
1788 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
1789 elif Option.quiet != None:\r
1790 EdkLogger.SetLevel(EdkLogger.QUIET)\r
1791 elif Option.debug != None:\r
1792 EdkLogger.SetLevel(Option.debug + 1)\r
1793 else:\r
1794 EdkLogger.SetLevel(EdkLogger.INFO)\r
1795\r
1796 if Option.LogFile != None:\r
1797 EdkLogger.SetLogFile(Option.LogFile)\r
1798\r
1799 if Option.WarningAsError == True:\r
1800 EdkLogger.SetWarningAsError()\r
1801\r
1802 if platform.platform().find("Windows") >= 0:\r
1803 GlobalData.gIsWindows = True\r
1804 else:\r
1805 GlobalData.gIsWindows = False\r
1806\r
6780eef1
LG
1807 EdkLogger.quiet("Build environment: %s" % platform.platform())\r
1808 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));\r
52302d4d
LG
1809 ReturnCode = 0\r
1810 MyBuild = None\r
1811 try:\r
1812 if len(Target) == 0:\r
1813 Target = "all"\r
1814 elif len(Target) >= 2:\r
1815 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
1816 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
1817 else:\r
1818 Target = Target[0].lower()\r
1819\r
1820 if Target not in gSupportedTarget:\r
1821 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
1822 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
1823\r
1824 GlobalData.gGlobalDefines = ParseDefines(Option.Macros)\r
1825 #\r
1826 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
1827 #\r
1828 CheckEnvVariable()\r
1829 Workspace = os.getenv("WORKSPACE")\r
1830 #\r
1831 # Get files real name in workspace dir\r
1832 #\r
1833 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
1834\r
1835 WorkingDirectory = os.getcwd()\r
1836 if not Option.ModuleFile:\r
1837 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
1838 FileNum = len(FileList)\r
1839 if FileNum >= 2:\r
1840 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
1841 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
1842 elif FileNum == 1:\r
1843 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
1844\r
1845 if Option.ModuleFile:\r
1846 if os.path.isabs (Option.ModuleFile):\r
1847 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
1848 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
1849 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
1850 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
1851 if ErrorCode != 0:\r
1852 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1853\r
1854 if Option.PlatformFile != None:\r
1855 if os.path.isabs (Option.PlatformFile):\r
1856 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
1857 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
1858 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
1859 ErrorCode, ErrorInfo = Option.PlatformFile.Validate(".dsc", False)\r
1860 if ErrorCode != 0:\r
1861 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1862\r
1863 if Option.FdfFile != None:\r
1864 if os.path.isabs (Option.FdfFile):\r
1865 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
1866 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
1867 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
1868 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
1869 if ErrorCode != 0:\r
1870 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1871\r
f3decdc3
LG
1872 if Option.Flag != None and Option.Flag not in ['-c', '-s']:\r
1873 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
1874\r
52302d4d
LG
1875 MyBuild = Build(Target, Workspace, Option.PlatformFile, Option.ModuleFile,\r
1876 Option.TargetArch, Option.ToolChain, Option.BuildTarget,\r
4234283c 1877 Option.FdfFile, Option.RomImage, Option.FvImage, Option.CapName,\r
52302d4d
LG
1878 None, Option.SilentMode, Option.ThreadNumber,\r
1879 Option.SkipAutoGen, Option.Reparse, Option.SkuId, \r
f3decdc3 1880 Option.ReportFile, Option.ReportType, Option.Flag)\r
52302d4d
LG
1881 MyBuild.Launch()\r
1882 #MyBuild.DumpBuildData()\r
1883 except FatalError, X:\r
1884 if MyBuild != None:\r
1885 # for multi-thread build exits safely\r
1886 MyBuild.Relinquish()\r
1887 if Option != None and Option.debug != None:\r
1888 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1889 ReturnCode = X.args[0]\r
1890 except Warning, X:\r
1891 # error from Fdf parser\r
1892 if MyBuild != None:\r
1893 # for multi-thread build exits safely\r
1894 MyBuild.Relinquish()\r
1895 if Option != None and Option.debug != None:\r
1896 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1897 else:\r
1898 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)\r
1899 ReturnCode = FORMAT_INVALID\r
1900 except KeyboardInterrupt:\r
1901 ReturnCode = ABORT_ERROR\r
1902 if Option != None and Option.debug != None:\r
1903 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1904 except:\r
1905 if MyBuild != None:\r
1906 # for multi-thread build exits safely\r
1907 MyBuild.Relinquish()\r
1908\r
1909 # try to get the meta-file from the object causing exception\r
1910 Tb = sys.exc_info()[-1]\r
1911 MetaFile = GlobalData.gProcessingFile\r
1912 while Tb != None:\r
1913 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
1914 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
1915 Tb = Tb.tb_next\r
1916 EdkLogger.error(\r
1917 "\nbuild",\r
1918 CODE_ERROR,\r
1919 "Unknown fatal error when processing [%s]" % MetaFile,\r
1920 ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",\r
1921 RaiseError=False\r
1922 )\r
1923 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1924 ReturnCode = CODE_ERROR\r
1925 finally:\r
1926 Utils.Progressor.Abort()\r
1927\r
1928 if ReturnCode == 0:\r
1929 Conclusion = "Done"\r
1930 elif ReturnCode == ABORT_ERROR:\r
1931 Conclusion = "Aborted"\r
1932 else:\r
1933 Conclusion = "Failed"\r
1934 FinishTime = time.time()\r
4234283c
LG
1935 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))\r
1936 BuildDurationStr = ""\r
1937 if BuildDuration.tm_yday > 1:\r
1938 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)"%(BuildDuration.tm_yday - 1)\r
1939 else:\r
1940 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)\r
52302d4d 1941 if MyBuild != None:\r
4234283c 1942 MyBuild.BuildReport.GenerateReport(BuildDurationStr)\r
52302d4d
LG
1943 MyBuild.Db.Close()\r
1944 EdkLogger.SetLevel(EdkLogger.QUIET)\r
6780eef1
LG
1945 EdkLogger.quiet("\n- %s -" % Conclusion)\r
1946 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
4234283c 1947 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
52302d4d
LG
1948 return ReturnCode\r
1949\r
1950if __name__ == '__main__':\r
1951 r = Main()\r
1952 ## 0-127 is a safe return range, and 1 is a standard default error\r
1953 if r < 0 or r > 127: r = 1\r
1954 sys.exit(r)\r
1955\r