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