]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/build.py
NetworkPkg/IpSecDxe: Fix wrong IKE header "FLAG" update
[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
40b4e21d 789 self.ToolChainFamily = None\r
52302d4d 790 self.LoadFixAddress = 0\r
0d2711a6 791 self.UniFlag = BuildOptions.Flag\r
a0a2cd1e 792 self.BuildModules = []\r
f0dc69e6
YZ
793 self.Db_Flag = False\r
794 self.LaunchPrebuildFlag = False\r
795 self.PrebuildScript = ''\r
796 self.PostbuildScript = ''\r
797 self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory,'.cache', '.PlatformBuild')\r
725cdb8f
YZ
798 if BuildOptions.CommandLength:\r
799 GlobalData.gCommandMaxLength = BuildOptions.CommandLength\r
800\r
e56468c0 801 # print dot character during doing some time-consuming work\r
52302d4d 802 self.Progress = Utils.Progressor()\r
52302d4d 803 # print current build environment and configuration\r
0d2711a6 804 EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))\r
f25da33d
LG
805 if "PACKAGES_PATH" in os.environ:\r
806 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env. \r
807 EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))\r
0d2711a6
LG
808 EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))\r
809 EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))\r
810 EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))\r
811 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))\r
f25da33d
LG
812 if "EDK_TOOLS_BIN" in os.environ:\r
813 # Print the same path style with WORKSPACE env. \r
814 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))\r
0d2711a6 815\r
f0dc69e6
YZ
816 self.InitPreBuild()\r
817 self.InitPostBuild()\r
818 if self.PrebuildScript:\r
819 EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.PrebuildScript))\r
820 if self.PostbuildScript:\r
821 EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.PostbuildScript))\r
822 if self.PrebuildScript:\r
823 self.LaunchPrebuild()\r
824 if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):\r
825 self.InitBuild()\r
52302d4d 826\r
f0dc69e6 827 EdkLogger.info("")\r
52302d4d 828 os.chdir(self.WorkspaceDir)\r
52302d4d
LG
829\r
830 ## Load configuration\r
831 #\r
832 # This method will parse target.txt and get the build configurations.\r
833 #\r
834 def LoadConfiguration(self):\r
835 #\r
836 # Check target.txt and tools_def.txt and Init them\r
837 #\r
97fa0ee9 838 BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))\r
52302d4d
LG
839 if os.path.isfile(BuildConfigurationFile) == True:\r
840 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)\r
841\r
842 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
843 if ToolDefinitionFile == '':\r
844 ToolDefinitionFile = gToolsDefinition\r
05cc51ad 845 ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))\r
52302d4d
LG
846 if os.path.isfile(ToolDefinitionFile) == True:\r
847 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)\r
848 else:\r
849 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)\r
850 else:\r
851 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
852\r
853 # if no ARCH given in command line, get it from target.txt\r
0d2711a6 854 if not self.ArchList:\r
52302d4d 855 self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]\r
0d2711a6 856 self.ArchList = tuple(self.ArchList)\r
52302d4d
LG
857\r
858 # if no build target given in command line, get it from target.txt\r
0d2711a6 859 if not self.BuildTargetList:\r
52302d4d
LG
860 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]\r
861\r
862 # if no tool chain given in command line, get it from target.txt\r
0d2711a6 863 if not self.ToolChainList:\r
52302d4d
LG
864 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
865 if self.ToolChainList == None or len(self.ToolChainList) == 0:\r
866 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")\r
867\r
868 # check if the tool chains are defined or not\r
869 NewToolChainList = []\r
870 for ToolChain in self.ToolChainList:\r
871 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
872 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)\r
873 else:\r
874 NewToolChainList.append(ToolChain)\r
875 # if no tool chain available, break the build\r
876 if len(NewToolChainList) == 0:\r
877 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
878 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))\r
879 else:\r
880 self.ToolChainList = NewToolChainList\r
881\r
40b4e21d
YZ
882 ToolChainFamily = []\r
883 ToolDefinition = self.ToolDef.ToolsDefTxtDatabase\r
884 for Tool in self.ToolChainList:\r
885 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \\r
886 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:\r
887 EdkLogger.warn("No tool chain family found in configuration for %s. Default to MSFT." % Tool)\r
888 ToolChainFamily.append("MSFT")\r
889 else:\r
890 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])\r
891 self.ToolChainFamily = ToolChainFamily\r
892\r
52302d4d
LG
893 if self.ThreadNumber == None:\r
894 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
895 if self.ThreadNumber == '':\r
896 self.ThreadNumber = 0\r
897 else:\r
898 self.ThreadNumber = int(self.ThreadNumber, 0)\r
899\r
900 if self.ThreadNumber == 0:\r
901 self.ThreadNumber = 1\r
902\r
903 if not self.PlatformFile:\r
904 PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
905 if not PlatformFile:\r
906 # Try to find one in current directory\r
907 WorkingDirectory = os.getcwd()\r
908 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
909 FileNum = len(FileList)\r
910 if FileNum >= 2:\r
911 EdkLogger.error("build", OPTION_MISSING,\r
912 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
913 elif FileNum == 1:\r
914 PlatformFile = FileList[0]\r
915 else:\r
916 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
917 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
918\r
919 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
52302d4d
LG
920\r
921 ## Initialize build configuration\r
922 #\r
923 # This method will parse DSC file and merge the configurations from\r
924 # command line and target.txt, then get the final build configurations.\r
925 #\r
926 def InitBuild(self):\r
0d2711a6 927 # parse target.txt, tools_def.txt, and platform file\r
4afd3d04 928 self.LoadConfiguration()\r
0d2711a6
LG
929\r
930 # Allow case-insensitive for those from command line or configuration file\r
931 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
52302d4d
LG
932 if ErrorCode != 0:\r
933 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
934\r
935 # create metafile database\r
f0dc69e6
YZ
936 if not self.Db_Flag:\r
937 self.Db.InitDatabase()\r
938\r
939 def InitPreBuild(self):\r
940 self.LoadConfiguration()\r
d429fcd0
YZ
941 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
942 if ErrorCode != 0:\r
943 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
f0dc69e6
YZ
944 if self.BuildTargetList:\r
945 GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]\r
946 if self.ArchList:\r
947 GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]\r
948 if self.ToolChainList:\r
949 GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]\r
950 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]\r
40b4e21d
YZ
951 if self.ToolChainFamily:\r
952 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]\r
f0dc69e6
YZ
953 if 'PREBUILD' in GlobalData.gCommandLineDefines.keys():\r
954 self.Prebuild = GlobalData.gCommandLineDefines.get('PREBUILD')\r
955 else:\r
956 self.Db.InitDatabase()\r
957 self.Db_Flag = True\r
958 Platform = self.Db._MapPlatform(str(self.PlatformFile))\r
959 self.Prebuild = str(Platform.Prebuild)\r
960 if self.Prebuild:\r
961 PrebuildList = self.Prebuild.split()\r
962 if not os.path.isabs(PrebuildList[0]):\r
963 PrebuildList[0] = mws.join(self.WorkspaceDir, PrebuildList[0])\r
964 if os.path.isfile(PrebuildList[0]):\r
965 self.PrebuildScript = PrebuildList[0]\r
966 self.Prebuild = ' '.join(PrebuildList)\r
967 self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList)\r
968 #self.LaunchPrebuild()\r
969 else:\r
970 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 971\r
f0dc69e6
YZ
972 def InitPostBuild(self):\r
973 if 'POSTBUILD' in GlobalData.gCommandLineDefines.keys():\r
974 self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')\r
975 else:\r
976 Platform = self.Db._MapPlatform(str(self.PlatformFile))\r
977 self.Postbuild = str(Platform.Postbuild)\r
978 if self.Postbuild:\r
979 PostbuildList = self.Postbuild.split()\r
980 if not os.path.isabs(PostbuildList[0]):\r
981 PostbuildList[0] = mws.join(self.WorkspaceDir, PostbuildList[0])\r
982 if os.path.isfile(PostbuildList[0]):\r
983 self.PostbuildScript = PostbuildList[0]\r
984 self.Postbuild = ' '.join(PostbuildList)\r
985 self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList)\r
986 #self.LanuchPostbuild()\r
987 else:\r
988 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
989\r
990 def PassCommandOption(self, BuildTarget, TargetArch, ToolChain):\r
991 BuildStr = ''\r
992 if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):\r
993 BuildStr += ' ' + ' '.join(GlobalData.gCommand)\r
994 TargetFlag = False\r
995 ArchFlag = False\r
996 ToolChainFlag = False\r
997\r
998 if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:\r
999 TargetFlag = True\r
1000 if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:\r
1001 ArchFlag = True\r
1002 if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:\r
1003 ToolChainFlag = True\r
1004\r
1005 if TargetFlag and BuildTarget:\r
1006 if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):\r
1007 BuildStr += ' -b ' + ' -b '.join(BuildTarget)\r
1008 elif isinstance(BuildTarget, str):\r
1009 BuildStr += ' -b ' + BuildTarget\r
1010 if ArchFlag and TargetArch:\r
1011 if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):\r
1012 BuildStr += ' -a ' + ' -a '.join(TargetArch)\r
1013 elif isinstance(TargetArch, str):\r
1014 BuildStr += ' -a ' + TargetArch\r
1015 if ToolChainFlag and ToolChain:\r
1016 if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):\r
1017 BuildStr += ' -t ' + ' -t '.join(ToolChain)\r
1018 elif isinstance(ToolChain, str):\r
1019 BuildStr += ' -t ' + ToolChain\r
1020\r
1021 return BuildStr\r
1022\r
1023 def LaunchPrebuild(self):\r
1024 if self.Prebuild:\r
1025 EdkLogger.info("\n- Prebuild Start -\n")\r
1026 self.LaunchPrebuildFlag = True\r
1027 PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory,'.cache','.PrebuildEnv')\r
1028 if os.path.isfile(PrebuildEnvFile):\r
1029 os.remove(PrebuildEnvFile)\r
1030 if os.path.isfile(self.PlatformBuildPath):\r
1031 os.remove(self.PlatformBuildPath)\r
1032 if sys.platform == "win32":\r
1033 args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))\r
1034 Process = Popen(args, stdout=PIPE, stderr=PIPE)\r
1035 else:\r
1036 args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))\r
1037 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True, executable="/bin/bash")\r
1038\r
1039 # launch two threads to read the STDOUT and STDERR\r
1040 EndOfProcedure = Event()\r
1041 EndOfProcedure.clear()\r
1042 if Process.stdout:\r
1043 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1044 StdOutThread.setName("STDOUT-Redirector")\r
1045 StdOutThread.setDaemon(False)\r
1046 StdOutThread.start()\r
1047\r
1048 if Process.stderr:\r
1049 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1050 StdErrThread.setName("STDERR-Redirector")\r
1051 StdErrThread.setDaemon(False)\r
1052 StdErrThread.start()\r
1053 # waiting for program exit\r
1054 Process.wait()\r
1055\r
1056 if Process.stdout:\r
1057 StdOutThread.join()\r
1058 if Process.stderr:\r
1059 StdErrThread.join()\r
1060 if Process.returncode != 0 :\r
1061 EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')\r
1062\r
1063 if os.path.exists(PrebuildEnvFile):\r
1064 f = open(PrebuildEnvFile)\r
1065 envs = f.readlines()\r
1066 f.close()\r
1067 envs = itertools.imap(lambda l: l.split('=',1), envs)\r
1068 envs = itertools.ifilter(lambda l: len(l) == 2, envs)\r
1069 envs = itertools.imap(lambda l: [i.strip() for i in l], envs)\r
1070 os.environ.update(dict(envs))\r
1071 EdkLogger.info("\n- Prebuild Done -\n")\r
1072\r
1073 def LanuchPostbuild(self):\r
1074 if self.Postbuild:\r
1075 EdkLogger.info("\n- Postbuild Start -\n")\r
1076 if sys.platform == "win32":\r
1077 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE)\r
1078 else:\r
1079 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True, executable="/bin/bash")\r
1080 # launch two threads to read the STDOUT and STDERR\r
1081 EndOfProcedure = Event()\r
1082 EndOfProcedure.clear()\r
1083 if Process.stdout:\r
1084 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1085 StdOutThread.setName("STDOUT-Redirector")\r
1086 StdOutThread.setDaemon(False)\r
1087 StdOutThread.start()\r
1088\r
1089 if Process.stderr:\r
1090 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1091 StdErrThread.setName("STDERR-Redirector")\r
1092 StdErrThread.setDaemon(False)\r
1093 StdErrThread.start()\r
1094 # waiting for program exit\r
1095 Process.wait()\r
1096\r
1097 if Process.stdout:\r
1098 StdOutThread.join()\r
1099 if Process.stderr:\r
1100 StdErrThread.join()\r
1101 if Process.returncode != 0 :\r
1102 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')\r
1103 EdkLogger.info("\n- Postbuild Done -\n")\r
52302d4d
LG
1104 ## Build a module or platform\r
1105 #\r
08dd311f 1106 # Create autogen code and makefile for a module or platform, and the launch\r
52302d4d
LG
1107 # "make" command to build it\r
1108 #\r
1109 # @param Target The target of build command\r
1110 # @param Platform The platform file\r
1111 # @param Module The module file\r
1112 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1113 # @param ToolChain The name of toolchain to build\r
1114 # @param Arch The arch of the module/platform\r
1115 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1116 # for dependent modules/Libraries\r
1117 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1118 # for dependent modules/Libraries\r
1119 #\r
03af2753 1120 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
52302d4d
LG
1121 if AutoGenObject == None:\r
1122 return False\r
1123\r
1124 # skip file generation for cleanxxx targets, run and fds target\r
1125 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1126 # for target which must generate AutoGen code and makefile\r
1127 if not self.SkipAutoGen or Target == 'genc':\r
1128 self.Progress.Start("Generating code")\r
1129 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1130 self.Progress.Stop("done!")\r
1131 if Target == "genc":\r
1132 return True\r
1133\r
1134 if not self.SkipAutoGen or Target == 'genmake':\r
1135 self.Progress.Start("Generating makefile")\r
1136 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
1137 self.Progress.Stop("done!")\r
1138 if Target == "genmake":\r
1139 return True\r
1140 else:\r
1141 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1142 AutoGenObject.CreateCodeFile(False)\r
1143 AutoGenObject.CreateMakeFile(False)\r
1144\r
1145 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1146 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1147\r
1148 BuildCommand = AutoGenObject.BuildCommand\r
1149 if BuildCommand == None or len(BuildCommand) == 0:\r
0d2711a6
LG
1150 EdkLogger.error("build", OPTION_MISSING,\r
1151 "No build command found for this module. "\r
4afd3d04 1152 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
0d2711a6
LG
1153 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1154 ExtraData=str(AutoGenObject))\r
52302d4d 1155\r
03af2753
HC
1156 makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]\r
1157\r
03af2753
HC
1158 # run\r
1159 if Target == 'run':\r
997a5d1b 1160 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
03af2753
HC
1161 Command = '.\SecMain'\r
1162 os.chdir(RunDir)\r
1163 LaunchCommand(Command, RunDir)\r
1164 return True\r
1165\r
1166 # build modules\r
1167 if BuildModule:\r
1168 BuildCommand = BuildCommand + [Target]\r
1169 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
a0a2cd1e 1170 self.CreateAsBuiltInf()\r
03af2753
HC
1171 return True\r
1172\r
1173 # build library\r
1174 if Target == 'libraries':\r
1175 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1176 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
1177 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1178 return True\r
1179\r
1180 # build module\r
1181 if Target == 'modules':\r
1182 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1183 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
1184 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1185 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1186 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']\r
1187 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
a0a2cd1e 1188 self.CreateAsBuiltInf()\r
03af2753
HC
1189 return True\r
1190\r
1191 # cleanlib\r
1192 if Target == 'cleanlib':\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 # clean\r
1201 if Target == 'clean':\r
1202 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1203 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))\r
1204 if os.path.exists(ModMakefile):\r
1205 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']\r
1206 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1207 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1208 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1209 if os.path.exists(LibMakefile):\r
1210 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1211 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1212 return True\r
1213\r
1214 # cleanall\r
1215 if Target == 'cleanall':\r
1216 try:\r
1217 #os.rmdir(AutoGenObject.BuildDir)\r
1218 RemoveDirectory(AutoGenObject.BuildDir, True)\r
03af2753
HC
1219 except WindowsError, X:\r
1220 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1221 return True\r
1222\r
1223 ## Build a module or platform\r
1224 #\r
1225 # Create autogen code and makefile for a module or platform, and the launch\r
1226 # "make" command to build it\r
1227 #\r
1228 # @param Target The target of build command\r
1229 # @param Platform The platform file\r
1230 # @param Module The module file\r
1231 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1232 # @param ToolChain The name of toolchain to build\r
1233 # @param Arch The arch of the module/platform\r
1234 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1235 # for dependent modules/Libraries\r
1236 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1237 # for dependent modules/Libraries\r
1238 #\r
1239 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
1240 if AutoGenObject == None:\r
1241 return False\r
1242\r
1243 # skip file generation for cleanxxx targets, run and fds target\r
1244 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1245 # for target which must generate AutoGen code and makefile\r
1246 if not self.SkipAutoGen or Target == 'genc':\r
1247 self.Progress.Start("Generating code")\r
1248 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1249 self.Progress.Stop("done!")\r
1250 if Target == "genc":\r
1251 return True\r
1252\r
1253 if not self.SkipAutoGen or Target == 'genmake':\r
1254 self.Progress.Start("Generating makefile")\r
1255 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
1256 #AutoGenObject.CreateAsBuiltInf()\r
1257 self.Progress.Stop("done!")\r
1258 if Target == "genmake":\r
1259 return True\r
1260 else:\r
1261 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1262 AutoGenObject.CreateCodeFile(False)\r
1263 AutoGenObject.CreateMakeFile(False)\r
1264\r
1265 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1266 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1267\r
1268 BuildCommand = AutoGenObject.BuildCommand\r
1269 if BuildCommand == None or len(BuildCommand) == 0:\r
1270 EdkLogger.error("build", OPTION_MISSING,\r
1271 "No build command found for this module. "\r
1272 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
1273 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1274 ExtraData=str(AutoGenObject))\r
1275\r
b0e23cf3
YL
1276 # build modules\r
1277 if BuildModule:\r
1278 if Target != 'fds':\r
1279 BuildCommand = BuildCommand + [Target]\r
1280 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
1281 self.CreateAsBuiltInf()\r
1282 return True\r
1283\r
03af2753
HC
1284 # genfds\r
1285 if Target == 'fds':\r
1286 LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)\r
1287 return True\r
1288\r
1289 # run\r
1290 if Target == 'run':\r
997a5d1b 1291 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
03af2753
HC
1292 Command = '.\SecMain'\r
1293 os.chdir(RunDir)\r
1294 LaunchCommand(Command, RunDir)\r
1295 return True\r
1296\r
03af2753
HC
1297 # build library\r
1298 if Target == 'libraries':\r
1299 pass\r
1300\r
1301 # not build modules\r
1302\r
1303\r
1304 # cleanall\r
52302d4d
LG
1305 if Target == 'cleanall':\r
1306 try:\r
1307 #os.rmdir(AutoGenObject.BuildDir)\r
1308 RemoveDirectory(AutoGenObject.BuildDir, True)\r
1309 except WindowsError, X:\r
1310 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1311 return True\r
1312\r
6780eef1 1313 ## Rebase module image and Get function address for the input module list.\r
52302d4d
LG
1314 #\r
1315 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
1316 if ModeIsSmm:\r
1317 AddrIsOffset = False\r
1318 InfFileNameList = ModuleList.keys()\r
1319 #InfFileNameList.sort()\r
1320 for InfFile in InfFileNameList:\r
da92f276
LG
1321 sys.stdout.write (".")\r
1322 sys.stdout.flush()\r
52302d4d
LG
1323 ModuleInfo = ModuleList[InfFile]\r
1324 ModuleName = ModuleInfo.BaseName\r
f3decdc3
LG
1325 ModuleOutputImage = ModuleInfo.Image.FileName\r
1326 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')\r
52302d4d
LG
1327 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1328 if not ModeIsSmm:\r
1329 BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
1330 #\r
1331 # Update Image to new BaseAddress by GenFw tool\r
1332 #\r
f3decdc3 1333 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
47fea6af 1334 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1335 else:\r
1336 #\r
1337 # Set new address to the section header only for SMM driver.\r
1338 #\r
f3decdc3 1339 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
47fea6af 1340 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1341 #\r
1342 # Collect funtion address from Map file\r
1343 #\r
f3decdc3 1344 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')\r
52302d4d
LG
1345 FunctionList = []\r
1346 if os.path.exists(ImageMapTable):\r
1347 OrigImageBaseAddress = 0\r
47fea6af 1348 ImageMap = open(ImageMapTable, 'r')\r
52302d4d
LG
1349 for LinStr in ImageMap:\r
1350 if len (LinStr.strip()) == 0:\r
1351 continue\r
1352 #\r
1353 # Get the preferred address set on link time.\r
1354 #\r
1355 if LinStr.find ('Preferred load address is') != -1:\r
1356 StrList = LinStr.split()\r
1357 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
1358\r
1359 StrList = LinStr.split()\r
1360 if len (StrList) > 4:\r
47fea6af 1361 if StrList[3] == 'f' or StrList[3] == 'F':\r
52302d4d
LG
1362 Name = StrList[1]\r
1363 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
1364 FunctionList.append ((Name, RelativeAddress))\r
1365 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):\r
1366 #\r
1367 # Get the real entry point address for IPF image.\r
1368 #\r
1369 ModuleInfo.Image.EntryPoint = RelativeAddress\r
1370 ImageMap.close()\r
1371 #\r
1372 # Add general information.\r
1373 #\r
1374 if ModeIsSmm:\r
1375 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1376 elif AddrIsOffset:\r
1377 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
1378 else:\r
1379 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1380 #\r
1381 # Add guid and general seciton section.\r
1382 #\r
1383 TextSectionAddress = 0\r
1384 DataSectionAddress = 0\r
1385 for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
1386 if SectionHeader[0] == '.text':\r
1387 TextSectionAddress = SectionHeader[1]\r
1388 elif SectionHeader[0] in ['.data', '.sdata']:\r
1389 DataSectionAddress = SectionHeader[1]\r
1390 if AddrIsOffset:\r
4afd3d04 1391 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))\r
52302d4d 1392 else:\r
4afd3d04 1393 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
f3decdc3
LG
1394 #\r
1395 # Add debug image full path.\r
1396 #\r
1397 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
52302d4d
LG
1398 #\r
1399 # Add funtion address\r
1400 #\r
1401 for Function in FunctionList:\r
1402 if AddrIsOffset:\r
1403 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
1404 else:\r
1405 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))\r
1406 ImageMap.close()\r
1407\r
1408 #\r
1409 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1410 #\r
1411 if ModeIsSmm:\r
1412 BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
1413\r
1414 ## Collect MAP information of all FVs\r
1415 #\r
636f2be6 1416 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):\r
0d2711a6 1417 if self.Fdf:\r
52302d4d 1418 # First get the XIP base address for FV map file.\r
636f2be6 1419 GuidPattern = re.compile("[-a-fA-F0-9]+")\r
f3decdc3 1420 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")\r
52302d4d
LG
1421 for FvName in Wa.FdfProfile.FvDict.keys():\r
1422 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
1423 if not os.path.exists(FvMapBuffer):\r
1424 continue\r
1be2ed90 1425 FvMap = open(FvMapBuffer, 'r')\r
52302d4d
LG
1426 #skip FV size information\r
1427 FvMap.readline()\r
1428 FvMap.readline()\r
1429 FvMap.readline()\r
1430 FvMap.readline()\r
636f2be6
LG
1431 for Line in FvMap:\r
1432 MatchGuid = GuidPattern.match(Line)\r
1433 if MatchGuid != None:\r
1434 #\r
1435 # Replace GUID with module name\r
1436 #\r
1437 GuidString = MatchGuid.group()\r
1438 if GuidString.upper() in ModuleList:\r
1439 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
1440 MapBuffer.write('%s' % (Line))\r
f3decdc3
LG
1441 #\r
1442 # Add the debug image full path.\r
1443 #\r
1444 MatchGuid = GuidName.match(Line)\r
1445 if MatchGuid != None:\r
1446 GuidString = MatchGuid.group().split("=")[1]\r
1447 if GuidString.upper() in ModuleList:\r
1448 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
1449\r
52302d4d
LG
1450 FvMap.close()\r
1451\r
1452 ## Collect MAP information of all modules\r
1453 #\r
1454 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
da92f276
LG
1455 sys.stdout.write ("Generate Load Module At Fix Address Map")\r
1456 sys.stdout.flush()\r
52302d4d
LG
1457 PatchEfiImageList = []\r
1458 PeiModuleList = {}\r
1459 BtModuleList = {}\r
1460 RtModuleList = {}\r
1461 SmmModuleList = {}\r
1462 PeiSize = 0\r
1463 BtSize = 0\r
1464 RtSize = 0\r
1465 # reserve 4K size in SMRAM to make SMM module address not from 0.\r
1466 SmmSize = 0x1000\r
1467 IsIpfPlatform = False\r
1468 if 'IPF' in self.ArchList:\r
1469 IsIpfPlatform = True\r
636f2be6
LG
1470 for ModuleGuid in ModuleList:\r
1471 Module = ModuleList[ModuleGuid]\r
52302d4d 1472 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
4afd3d04 1473\r
52302d4d
LG
1474 OutputImageFile = ''\r
1475 for ResultFile in Module.CodaTargetList:\r
1476 if str(ResultFile.Target).endswith('.efi'):\r
1477 #\r
1478 # module list for PEI, DXE, RUNTIME and SMM\r
1479 #\r
1480 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
1481 ImageClass = PeImageClass (OutputImageFile)\r
1482 if not ImageClass.IsValid:\r
1483 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
f3decdc3 1484 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)\r
47fea6af 1485 if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER', 'PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:\r
52302d4d
LG
1486 PeiModuleList[Module.MetaFile] = ImageInfo\r
1487 PeiSize += ImageInfo.Image.Size\r
1488 elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:\r
1489 BtModuleList[Module.MetaFile] = ImageInfo\r
1490 BtSize += ImageInfo.Image.Size\r
1491 elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:\r
1492 RtModuleList[Module.MetaFile] = ImageInfo\r
1493 #IPF runtime driver needs to be at 2 page alignment.\r
1494 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:\r
1495 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000\r
1496 RtSize += ImageInfo.Image.Size\r
1497 elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:\r
1498 SmmModuleList[Module.MetaFile] = ImageInfo\r
1499 SmmSize += ImageInfo.Image.Size\r
1500 if Module.ModuleType == 'DXE_SMM_DRIVER':\r
da92f276
LG
1501 PiSpecVersion = '0x00000000'\r
1502 if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:\r
1503 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']\r
52302d4d 1504 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
da92f276 1505 if int(PiSpecVersion, 16) < 0x0001000A:\r
52302d4d
LG
1506 BtModuleList[Module.MetaFile] = ImageInfo\r
1507 BtSize += ImageInfo.Image.Size\r
1508 break\r
1509 #\r
1510 # EFI image is final target.\r
1511 # Check EFI image contains patchable FixAddress related PCDs.\r
1512 #\r
1513 if OutputImageFile != '':\r
1514 ModuleIsPatch = False\r
1515 for Pcd in Module.ModulePcdList:\r
1516 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1517 ModuleIsPatch = True\r
1518 break\r
1519 if not ModuleIsPatch:\r
1520 for Pcd in Module.LibraryPcdList:\r
1521 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1522 ModuleIsPatch = True\r
1523 break\r
4afd3d04 1524\r
52302d4d
LG
1525 if not ModuleIsPatch:\r
1526 continue\r
1527 #\r
1528 # Module includes the patchable load fix address PCDs.\r
4afd3d04 1529 # It will be fixed up later.\r
52302d4d
LG
1530 #\r
1531 PatchEfiImageList.append (OutputImageFile)\r
4afd3d04 1532\r
52302d4d
LG
1533 #\r
1534 # Get Top Memory address\r
1535 #\r
1536 ReservedRuntimeMemorySize = 0\r
1537 TopMemoryAddress = 0\r
1538 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
1539 TopMemoryAddress = 0\r
1540 else:\r
1541 TopMemoryAddress = self.LoadFixAddress\r
1542 if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
1543 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
1544 # Make IPF runtime driver at 2 page alignment.\r
1545 if IsIpfPlatform:\r
1546 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000\r
1547 RtSize = RtSize + ReservedRuntimeMemorySize\r
1548\r
1549 #\r
1550 # Patch FixAddress related PCDs into EFI image\r
1551 #\r
4afd3d04 1552 for EfiImage in PatchEfiImageList:\r
52302d4d
LG
1553 EfiImageMap = EfiImage.replace('.efi', '.map')\r
1554 if not os.path.exists(EfiImageMap):\r
1555 continue\r
1556 #\r
1557 # Get PCD offset in EFI image by GenPatchPcdTable function\r
1558 #\r
4afd3d04 1559 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)\r
52302d4d
LG
1560 #\r
1561 # Patch real PCD value by PatchPcdValue tool\r
1562 #\r
1563 for PcdInfo in PcdTable:\r
1564 ReturnValue = 0\r
1565 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
47fea6af 1566 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000))\r
52302d4d 1567 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
47fea6af 1568 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000))\r
52302d4d 1569 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
47fea6af 1570 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000))\r
52302d4d 1571 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
47fea6af 1572 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000))\r
52302d4d
LG
1573 if ReturnValue != 0:\r
1574 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
4afd3d04 1575\r
47fea6af
YZ
1576 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize / 0x1000))\r
1577 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize / 0x1000))\r
1578 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize / 0x1000))\r
52302d4d 1579 if len (SmmModuleList) > 0:\r
47fea6af 1580 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize / 0x1000))\r
4afd3d04
LG
1581\r
1582 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
52302d4d 1583 BtBaseAddr = TopMemoryAddress - RtSize\r
4afd3d04 1584 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize\r
52302d4d
LG
1585\r
1586 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
1587 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
1588 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
47fea6af 1589 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)\r
52302d4d 1590 MapBuffer.write('\n\n')\r
da92f276
LG
1591 sys.stdout.write ("\n")\r
1592 sys.stdout.flush()\r
4afd3d04 1593\r
52302d4d
LG
1594 ## Save platform Map file\r
1595 #\r
1596 def _SaveMapFile (self, MapBuffer, Wa):\r
1597 #\r
1598 # Map file path is got.\r
1599 #\r
1600 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
1601 #\r
1602 # Save address map into MAP file.\r
1603 #\r
40d841f6 1604 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
da92f276
LG
1605 MapBuffer.close()\r
1606 if self.LoadFixAddress != 0:\r
47fea6af 1607 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))\r
da92f276 1608 sys.stdout.flush()\r
52302d4d
LG
1609\r
1610 ## Build active platform for different build targets and different tool chains\r
1611 #\r
1612 def _BuildPlatform(self):\r
f0dc69e6 1613 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
52302d4d 1614 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1615 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1616 index = 0\r
52302d4d 1617 for ToolChain in self.ToolChainList:\r
0d2711a6
LG
1618 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1619 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1620 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1621 index += 1\r
52302d4d
LG
1622 Wa = WorkspaceAutoGen(\r
1623 self.WorkspaceDir,\r
0d2711a6 1624 self.PlatformFile,\r
52302d4d
LG
1625 BuildTarget,\r
1626 ToolChain,\r
1627 self.ArchList,\r
1628 self.BuildDatabase,\r
1629 self.TargetTxt,\r
1630 self.ToolDef,\r
1631 self.Fdf,\r
1632 self.FdList,\r
1633 self.FvList,\r
4234283c 1634 self.CapList,\r
f3decdc3 1635 self.SkuId,\r
9508d0fa
LG
1636 self.UniFlag,\r
1637 self.Progress\r
52302d4d 1638 )\r
0d2711a6
LG
1639 self.Fdf = Wa.FdfFile\r
1640 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
1641 self.BuildReport.AddPlatformReport(Wa)\r
1642 self.Progress.Stop("done!")\r
03af2753
HC
1643 for Arch in Wa.ArchList:\r
1644 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1645 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
a0a2cd1e
FB
1646 for Module in Pa.Platform.Modules:\r
1647 # Get ModuleAutoGen object to generate C code file and makefile\r
1648 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1649 if Ma == None:\r
1650 continue\r
1651 self.BuildModules.append(Ma)\r
03af2753 1652 self._BuildPa(self.Target, Pa)\r
4afd3d04 1653\r
52302d4d 1654 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1655 if self.Target in ["", "all", "fds"]:\r
0d2711a6
LG
1656 for Arch in Wa.ArchList:\r
1657 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d
LG
1658 #\r
1659 # Check whether the set fix address is above 4G for 32bit image.\r
1660 #\r
1661 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
0d2711a6 1662 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
1663 #\r
1664 # Get Module List\r
1665 #\r
636f2be6 1666 ModuleList = {}\r
52302d4d
LG
1667 for Pa in Wa.AutoGenObjectList:\r
1668 for Ma in Pa.ModuleAutoGenList:\r
1669 if Ma == None:\r
1670 continue\r
1671 if not Ma.IsLibrary:\r
636f2be6 1672 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1673\r
1674 MapBuffer = StringIO('')\r
636f2be6
LG
1675 if self.LoadFixAddress != 0:\r
1676 #\r
1677 # Rebase module to the preferred memory address before GenFds\r
1678 #\r
1679 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
0d2711a6 1680 if self.Fdf:\r
b0e23cf3
YL
1681 #\r
1682 # create FDS again for the updated EFI image\r
1683 #\r
1684 self._Build("fds", Wa)\r
52302d4d
LG
1685 #\r
1686 # Create MAP file for all platform FVs after GenFds.\r
1687 #\r
636f2be6 1688 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1689 #\r
1690 # Save MAP buffer into MAP file.\r
1691 #\r
1692 self._SaveMapFile (MapBuffer, Wa)\r
1693\r
1694 ## Build active module for different build targets, different tool chains and different archs\r
1695 #\r
1696 def _BuildModule(self):\r
1697 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1698 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1699 index = 0\r
52302d4d 1700 for ToolChain in self.ToolChainList:\r
0d2711a6 1701 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 1702 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1703 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1704 index += 1\r
52302d4d
LG
1705 #\r
1706 # module build needs platform build information, so get platform\r
1707 # AutoGen first\r
1708 #\r
1709 Wa = WorkspaceAutoGen(\r
1710 self.WorkspaceDir,\r
0d2711a6 1711 self.PlatformFile,\r
52302d4d
LG
1712 BuildTarget,\r
1713 ToolChain,\r
1714 self.ArchList,\r
1715 self.BuildDatabase,\r
1716 self.TargetTxt,\r
1717 self.ToolDef,\r
1718 self.Fdf,\r
1719 self.FdList,\r
1720 self.FvList,\r
4234283c 1721 self.CapList,\r
f3decdc3 1722 self.SkuId,\r
9508d0fa
LG
1723 self.UniFlag,\r
1724 self.Progress,\r
1725 self.ModuleFile\r
52302d4d 1726 )\r
0d2711a6
LG
1727 self.Fdf = Wa.FdfFile\r
1728 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
1729 Wa.CreateMakeFile(False)\r
1730 self.Progress.Stop("done!")\r
1731 MaList = []\r
0d2711a6
LG
1732 for Arch in Wa.ArchList:\r
1733 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d
LG
1734 Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1735 if Ma == None: continue\r
1736 MaList.append(Ma)\r
a0a2cd1e 1737 self.BuildModules.append(Ma)\r
03af2753
HC
1738 if not Ma.IsBinaryModule:\r
1739 self._Build(self.Target, Ma, BuildModule=True)\r
d5d56f1b
LG
1740\r
1741 self.BuildReport.AddPlatformReport(Wa, MaList)\r
52302d4d
LG
1742 if MaList == []:\r
1743 EdkLogger.error(\r
1744 'build',\r
1745 BUILD_ERROR,\r
1746 "Module for [%s] is not a component of active platform."\\r
1747 " Please make sure that the ARCH and inf file path are"\\r
47fea6af 1748 " given in the same as in [%s]" % \\r
0d2711a6 1749 (', '.join(Wa.ArchList), self.PlatformFile),\r
52302d4d
LG
1750 ExtraData=self.ModuleFile\r
1751 )\r
1752 # Create MAP file when Load Fix Address is enabled.\r
0d2711a6
LG
1753 if self.Target == "fds" and self.Fdf:\r
1754 for Arch in Wa.ArchList:\r
52302d4d
LG
1755 #\r
1756 # Check whether the set fix address is above 4G for 32bit image.\r
1757 #\r
1758 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1759 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
1760 #\r
1761 # Get Module List\r
1762 #\r
636f2be6 1763 ModuleList = {}\r
52302d4d
LG
1764 for Pa in Wa.AutoGenObjectList:\r
1765 for Ma in Pa.ModuleAutoGenList:\r
1766 if Ma == None:\r
1767 continue\r
1768 if not Ma.IsLibrary:\r
636f2be6 1769 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1770\r
1771 MapBuffer = StringIO('')\r
636f2be6
LG
1772 if self.LoadFixAddress != 0:\r
1773 #\r
1774 # Rebase module to the preferred memory address before GenFds\r
1775 #\r
1776 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
b0e23cf3
YL
1777 #\r
1778 # create FDS again for the updated EFI image\r
1779 #\r
1780 self._Build("fds", Wa)\r
52302d4d
LG
1781 #\r
1782 # Create MAP file for all platform FVs after GenFds.\r
1783 #\r
636f2be6 1784 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1785 #\r
1786 # Save MAP buffer into MAP file.\r
1787 #\r
1788 self._SaveMapFile (MapBuffer, Wa)\r
1789\r
1790 ## Build a platform in multi-thread mode\r
1791 #\r
1792 def _MultiThreadBuildPlatform(self):\r
f0dc69e6 1793 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
52302d4d 1794 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1795 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1796 index = 0\r
52302d4d 1797 for ToolChain in self.ToolChainList:\r
0d2711a6 1798 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 1799 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1800 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1801 index += 1\r
52302d4d
LG
1802 Wa = WorkspaceAutoGen(\r
1803 self.WorkspaceDir,\r
0d2711a6 1804 self.PlatformFile,\r
52302d4d
LG
1805 BuildTarget,\r
1806 ToolChain,\r
1807 self.ArchList,\r
1808 self.BuildDatabase,\r
1809 self.TargetTxt,\r
1810 self.ToolDef,\r
1811 self.Fdf,\r
1812 self.FdList,\r
1813 self.FvList,\r
4234283c 1814 self.CapList,\r
f3decdc3 1815 self.SkuId,\r
9508d0fa
LG
1816 self.UniFlag,\r
1817 self.Progress\r
52302d4d 1818 )\r
0d2711a6
LG
1819 self.Fdf = Wa.FdfFile\r
1820 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
1821 self.BuildReport.AddPlatformReport(Wa)\r
1822 Wa.CreateMakeFile(False)\r
1823\r
1824 # multi-thread exit flag\r
1825 ExitFlag = threading.Event()\r
1826 ExitFlag.clear()\r
0d2711a6
LG
1827 for Arch in Wa.ArchList:\r
1828 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d
LG
1829 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1830 if Pa == None:\r
1831 continue\r
a0a2cd1e
FB
1832 ModuleList = []\r
1833 for Inf in Pa.Platform.Modules:\r
1834 ModuleList.append(Inf)\r
1835 # Add the INF only list in FDF\r
1836 if GlobalData.gFdfParser != None:\r
1837 for InfName in GlobalData.gFdfParser.Profile.InfList:\r
1838 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)\r
1839 if Inf in Pa.Platform.Modules:\r
1840 continue\r
1841 ModuleList.append(Inf)\r
1842 for Module in ModuleList:\r
52302d4d
LG
1843 # Get ModuleAutoGen object to generate C code file and makefile\r
1844 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
a0a2cd1e 1845 \r
52302d4d
LG
1846 if Ma == None:\r
1847 continue\r
1848 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1849 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1850 # for target which must generate AutoGen code and makefile\r
1851 if not self.SkipAutoGen or self.Target == 'genc':\r
1852 Ma.CreateCodeFile(True)\r
1853 if self.Target == "genc":\r
1854 continue\r
1855\r
1856 if not self.SkipAutoGen or self.Target == 'genmake':\r
1857 Ma.CreateMakeFile(True)\r
1858 if self.Target == "genmake":\r
1859 continue\r
a0a2cd1e 1860 self.BuildModules.append(Ma)\r
e8a47801 1861 self.Progress.Stop("done!")\r
4afd3d04 1862\r
a0a2cd1e 1863 for Ma in self.BuildModules:\r
52302d4d 1864 # Generate build task for the module\r
a0a2cd1e
FB
1865 if not Ma.IsBinaryModule:\r
1866 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
52302d4d
LG
1867 # Break build if any build thread has error\r
1868 if BuildTask.HasError():\r
1869 # we need a full version of makefile for platform\r
1870 ExitFlag.set()\r
1871 BuildTask.WaitForComplete()\r
1872 Pa.CreateMakeFile(False)\r
1873 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1874 # Start task scheduler\r
1875 if not BuildTask.IsOnGoing():\r
1876 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1877\r
1878 # in case there's an interruption. we need a full version of makefile for platform\r
1879 Pa.CreateMakeFile(False)\r
1880 if BuildTask.HasError():\r
1881 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1882\r
64b2609f
LG
1883 #\r
1884 # Save temp tables to a TmpTableDict.\r
1885 #\r
1886 for Key in Wa.BuildDatabase._CACHE_:\r
1887 if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:\r
1888 if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):\r
1889 TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur\r
1890 #\r
52302d4d
LG
1891 #\r
1892 # All modules have been put in build tasks queue. Tell task scheduler\r
1893 # to exit if all tasks are completed\r
1894 #\r
1895 ExitFlag.set()\r
1896 BuildTask.WaitForComplete()\r
a0a2cd1e 1897 self.CreateAsBuiltInf()\r
52302d4d
LG
1898\r
1899 #\r
1900 # Check for build error, and raise exception if one\r
1901 # has been signaled.\r
1902 #\r
1903 if BuildTask.HasError():\r
1904 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1905\r
1906 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1907 if self.Target in ["", "all", "fds"]:\r
0d2711a6 1908 for Arch in Wa.ArchList:\r
52302d4d
LG
1909 #\r
1910 # Check whether the set fix address is above 4G for 32bit image.\r
1911 #\r
1912 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1913 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
1914 #\r
1915 # Get Module List\r
1916 #\r
636f2be6 1917 ModuleList = {}\r
52302d4d
LG
1918 for Pa in Wa.AutoGenObjectList:\r
1919 for Ma in Pa.ModuleAutoGenList:\r
1920 if Ma == None:\r
1921 continue\r
1922 if not Ma.IsLibrary:\r
636f2be6 1923 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1924 #\r
1925 # Rebase module to the preferred memory address before GenFds\r
1926 #\r
1927 MapBuffer = StringIO('')\r
636f2be6
LG
1928 if self.LoadFixAddress != 0:\r
1929 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d 1930\r
0d2711a6 1931 if self.Fdf:\r
f3decdc3
LG
1932 #\r
1933 # Generate FD image if there's a FDF file found\r
1934 #\r
03af2753
HC
1935 LaunchCommand(Wa.GenFdsCommand, os.getcwd())\r
1936\r
52302d4d
LG
1937 #\r
1938 # Create MAP file for all platform FVs after GenFds.\r
1939 #\r
636f2be6 1940 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1941 #\r
1942 # Save MAP buffer into MAP file.\r
1943 #\r
1944 self._SaveMapFile(MapBuffer, Wa)\r
1945\r
1946 ## Generate GuidedSectionTools.txt in the FV directories.\r
1947 #\r
1948 def CreateGuidedSectionToolsFile(self):\r
0d2711a6
LG
1949 for BuildTarget in self.BuildTargetList:\r
1950 for ToolChain in self.ToolChainList:\r
1951 Wa = WorkspaceAutoGen(\r
1952 self.WorkspaceDir,\r
1953 self.PlatformFile,\r
1954 BuildTarget,\r
1955 ToolChain,\r
1956 self.ArchList,\r
1957 self.BuildDatabase,\r
1958 self.TargetTxt,\r
1959 self.ToolDef,\r
1960 self.Fdf,\r
1961 self.FdList,\r
1962 self.FvList,\r
1963 self.CapList,\r
1964 self.SkuId,\r
1965 self.UniFlag\r
1966 )\r
1967 FvDir = Wa.FvDir\r
1968 if not os.path.exists(FvDir):\r
1969 continue\r
1970\r
4afd3d04 1971 for Arch in self.ArchList:\r
52302d4d
LG
1972 # Build up the list of supported architectures for this build\r
1973 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
4afd3d04 1974\r
52302d4d
LG
1975 # Look through the tool definitions for GUIDed tools\r
1976 guidAttribs = []\r
1977 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
1978 if attrib.upper().endswith('_GUID'):\r
1979 split = attrib.split('_')\r
1980 thisPrefix = '_'.join(split[0:3]) + '_'\r
1981 if thisPrefix == prefix:\r
1982 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
1983 guid = guid.lower()\r
1984 toolName = split[3]\r
1985 path = '_'.join(split[0:4]) + '_PATH'\r
1986 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
1987 path = self.GetFullPathOfTool(path)\r
1988 guidAttribs.append((guid, toolName, path))\r
4afd3d04 1989\r
52302d4d
LG
1990 # Write out GuidedSecTools.txt\r
1991 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
1992 toolsFile = open(toolsFile, 'wt')\r
1993 for guidedSectionTool in guidAttribs:\r
1994 print >> toolsFile, ' '.join(guidedSectionTool)\r
1995 toolsFile.close()\r
1996\r
1997 ## Returns the full path of the tool.\r
1998 #\r
1999 def GetFullPathOfTool (self, tool):\r
2000 if os.path.exists(tool):\r
2001 return os.path.realpath(tool)\r
2002 else:\r
2003 # We need to search for the tool using the\r
2004 # PATH environment variable.\r
2005 for dirInPath in os.environ['PATH'].split(os.pathsep):\r
2006 foundPath = os.path.join(dirInPath, tool)\r
2007 if os.path.exists(foundPath):\r
2008 return os.path.realpath(foundPath)\r
2009\r
2010 # If the tool was not found in the path then we just return\r
2011 # the input tool.\r
2012 return tool\r
2013\r
2014 ## Launch the module or platform build\r
2015 #\r
2016 def Launch(self):\r
0d2711a6 2017 if not self.ModuleFile:\r
52302d4d
LG
2018 if not self.SpawnMode or self.Target not in ["", "all"]:\r
2019 self.SpawnMode = False\r
2020 self._BuildPlatform()\r
2021 else:\r
2022 self._MultiThreadBuildPlatform()\r
2023 self.CreateGuidedSectionToolsFile()\r
2024 else:\r
2025 self.SpawnMode = False\r
2026 self._BuildModule()\r
2027\r
bcbdc755
YL
2028 if self.Target == 'cleanall':\r
2029 self.Db.Close()\r
2030 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)\r
2031\r
a0a2cd1e
FB
2032 def CreateAsBuiltInf(self):\r
2033 for Module in self.BuildModules:\r
2034 Module.CreateAsBuiltInf()\r
2035 self.BuildModules = []\r
52302d4d
LG
2036 ## Do some clean-up works when error occurred\r
2037 def Relinquish(self):\r
2038 OldLogLevel = EdkLogger.GetLevel()\r
2039 EdkLogger.SetLevel(EdkLogger.ERROR)\r
2040 #self.DumpBuildData()\r
2041 Utils.Progressor.Abort()\r
2042 if self.SpawnMode == True:\r
2043 BuildTask.Abort()\r
2044 EdkLogger.SetLevel(OldLogLevel)\r
2045\r
2046 def DumpBuildData(self):\r
97fa0ee9 2047 CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)\r
52302d4d
LG
2048 Utils.CreateDirectory(CacheDirectory)\r
2049 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
2050 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
2051\r
2052 def RestoreBuildData(self):\r
97fa0ee9 2053 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")\r
52302d4d
LG
2054 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
2055 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
2056 if Utils.gFileTimeStampCache == None:\r
2057 Utils.gFileTimeStampCache = {}\r
2058\r
97fa0ee9 2059 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")\r
52302d4d
LG
2060 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
2061 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
2062 if Utils.gDependencyDatabase == None:\r
2063 Utils.gDependencyDatabase = {}\r
2064\r
2065def ParseDefines(DefineList=[]):\r
2066 DefineDict = {}\r
2067 if DefineList != None:\r
2068 for Define in DefineList:\r
2069 DefineTokenList = Define.split("=", 1)\r
0d2711a6
LG
2070 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):\r
2071 EdkLogger.error('build', FORMAT_INVALID,\r
2072 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",\r
2073 ExtraData=DefineTokenList[0])\r
4afd3d04 2074\r
52302d4d 2075 if len(DefineTokenList) == 1:\r
0d2711a6 2076 DefineDict[DefineTokenList[0]] = "TRUE"\r
52302d4d
LG
2077 else:\r
2078 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
2079 return DefineDict\r
2080\r
2081gParamCheck = []\r
2082def SingleCheckCallback(option, opt_str, value, parser):\r
2083 if option not in gParamCheck:\r
2084 setattr(parser.values, option.dest, value)\r
2085 gParamCheck.append(option)\r
2086 else:\r
2087 parser.error("Option %s only allows one instance in command line!" % option)\r
2088\r
2089## Parse command line options\r
2090#\r
2091# Using standard Python module optparse to parse command line option of this tool.\r
2092#\r
2093# @retval Opt A optparse.Values object containing the parsed options\r
2094# @retval Args Target of build command\r
2095#\r
2096def MyOptionParser():\r
47fea6af
YZ
2097 Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")\r
2098 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch",\r
4afd3d04 2099 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
2100 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
2101 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
2102 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
2103 help="Build the module specified by the INF file name argument.")\r
64b2609f
LG
2104 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",\r
2105 action="append")\r
52302d4d
LG
2106 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
2107 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
2108 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
2109 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
2110\r
2111 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
2112 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
2113\r
2114 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
2115 help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
2116 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
2117 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
2118 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
2119 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
4234283c
LG
2120 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],\r
2121 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")\r
52302d4d
LG
2122 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
2123 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
2124\r
0d2711a6 2125 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")\r
52302d4d
LG
2126\r
2127 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
2128 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
2129\r
2130 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
2131 help="Make use of silent mode of (n)make.")\r
2132 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
2133 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
2134 "including library instances selected, final dependency expression, "\\r
2135 "and warning messages, etc.")\r
2136 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
2137 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
2138\r
2139 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
eca5be7a
YZ
2140 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
2141 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 2142 "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
2143 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",\r
2144 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
2145 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\\r
2146 "will override the setting in [BuildOptions] section of platform DSC.")\r
0d2711a6 2147 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")\r
97fa0ee9
YL
2148 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")\r
2149 Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")\r
fae62ff2 2150 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 2151 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")\r
725cdb8f 2152 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 2153\r
47fea6af 2154 (Opt, Args) = Parser.parse_args()\r
52302d4d
LG
2155 return (Opt, Args)\r
2156\r
2157## Tool entrance method\r
2158#\r
2159# This method mainly dispatch specific methods per the command line options.\r
2160# If no error found, return zero value so the caller of this tool can know\r
2161# if it's executed successfully or not.\r
2162#\r
2163# @retval 0 Tool was successful\r
2164# @retval 1 Tool failed\r
2165#\r
2166def Main():\r
2167 StartTime = time.time()\r
2168\r
2169 # Initialize log system\r
2170 EdkLogger.Initialize()\r
f0dc69e6 2171 GlobalData.gCommand = sys.argv[1:]\r
52302d4d
LG
2172 #\r
2173 # Parse the options and args\r
2174 #\r
2175 (Option, Target) = MyOptionParser()\r
2176 GlobalData.gOptions = Option\r
2177 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
2178\r
2179 # Set log level\r
2180 if Option.verbose != None:\r
2181 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
2182 elif Option.quiet != None:\r
2183 EdkLogger.SetLevel(EdkLogger.QUIET)\r
2184 elif Option.debug != None:\r
2185 EdkLogger.SetLevel(Option.debug + 1)\r
2186 else:\r
2187 EdkLogger.SetLevel(EdkLogger.INFO)\r
2188\r
2189 if Option.LogFile != None:\r
2190 EdkLogger.SetLogFile(Option.LogFile)\r
2191\r
2192 if Option.WarningAsError == True:\r
2193 EdkLogger.SetWarningAsError()\r
2194\r
2195 if platform.platform().find("Windows") >= 0:\r
2196 GlobalData.gIsWindows = True\r
2197 else:\r
2198 GlobalData.gIsWindows = False\r
2199\r
6780eef1
LG
2200 EdkLogger.quiet("Build environment: %s" % platform.platform())\r
2201 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));\r
52302d4d
LG
2202 ReturnCode = 0\r
2203 MyBuild = None\r
09ae0f11 2204 BuildError = True\r
52302d4d
LG
2205 try:\r
2206 if len(Target) == 0:\r
2207 Target = "all"\r
2208 elif len(Target) >= 2:\r
2209 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
47fea6af 2210 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d
LG
2211 else:\r
2212 Target = Target[0].lower()\r
2213\r
2214 if Target not in gSupportedTarget:\r
2215 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
47fea6af 2216 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d 2217\r
52302d4d
LG
2218 #\r
2219 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
2220 #\r
2221 CheckEnvVariable()\r
0d2711a6
LG
2222 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))\r
2223\r
52302d4d
LG
2224 Workspace = os.getenv("WORKSPACE")\r
2225 #\r
2226 # Get files real name in workspace dir\r
2227 #\r
2228 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
2229\r
2230 WorkingDirectory = os.getcwd()\r
2231 if not Option.ModuleFile:\r
2232 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
2233 FileNum = len(FileList)\r
2234 if FileNum >= 2:\r
2235 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
2236 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
2237 elif FileNum == 1:\r
2238 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
2239\r
2240 if Option.ModuleFile:\r
2241 if os.path.isabs (Option.ModuleFile):\r
2242 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
2243 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
2244 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
2245 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
2246 if ErrorCode != 0:\r
2247 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2248\r
2249 if Option.PlatformFile != None:\r
2250 if os.path.isabs (Option.PlatformFile):\r
2251 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
2252 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
2253 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
52302d4d
LG
2254\r
2255 if Option.FdfFile != None:\r
2256 if os.path.isabs (Option.FdfFile):\r
2257 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
2258 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
2259 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
2260 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
2261 if ErrorCode != 0:\r
2262 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2263\r
f3decdc3
LG
2264 if Option.Flag != None and Option.Flag not in ['-c', '-s']:\r
2265 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
2266\r
0d2711a6 2267 MyBuild = Build(Target, Workspace, Option)\r
64b2609f 2268 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)\r
f0dc69e6
YZ
2269 if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):\r
2270 MyBuild.Launch()\r
64b2609f
LG
2271 # Drop temp tables to avoid database locked.\r
2272 for TmpTableName in TmpTableDict:\r
2273 SqlCommand = """drop table IF EXISTS %s""" % TmpTableName\r
2274 TmpTableDict[TmpTableName].execute(SqlCommand)\r
52302d4d 2275 #MyBuild.DumpBuildData()\r
09ae0f11
YL
2276 #\r
2277 # All job done, no error found and no exception raised\r
2278 #\r
2279 BuildError = False\r
52302d4d
LG
2280 except FatalError, X:\r
2281 if MyBuild != None:\r
2282 # for multi-thread build exits safely\r
2283 MyBuild.Relinquish()\r
2284 if Option != None and Option.debug != None:\r
2285 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2286 ReturnCode = X.args[0]\r
2287 except Warning, X:\r
2288 # error from Fdf parser\r
2289 if MyBuild != None:\r
2290 # for multi-thread build exits safely\r
2291 MyBuild.Relinquish()\r
2292 if Option != None and Option.debug != None:\r
2293 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2294 else:\r
47fea6af 2295 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
52302d4d
LG
2296 ReturnCode = FORMAT_INVALID\r
2297 except KeyboardInterrupt:\r
2298 ReturnCode = ABORT_ERROR\r
2299 if Option != None and Option.debug != None:\r
2300 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2301 except:\r
2302 if MyBuild != None:\r
2303 # for multi-thread build exits safely\r
2304 MyBuild.Relinquish()\r
2305\r
2306 # try to get the meta-file from the object causing exception\r
2307 Tb = sys.exc_info()[-1]\r
2308 MetaFile = GlobalData.gProcessingFile\r
2309 while Tb != None:\r
2310 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
2311 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
2312 Tb = Tb.tb_next\r
2313 EdkLogger.error(\r
2314 "\nbuild",\r
2315 CODE_ERROR,\r
2316 "Unknown fatal error when processing [%s]" % MetaFile,\r
3a0f8bde 2317 ExtraData="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",\r
52302d4d
LG
2318 RaiseError=False\r
2319 )\r
d0acc87a 2320 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
52302d4d
LG
2321 ReturnCode = CODE_ERROR\r
2322 finally:\r
2323 Utils.Progressor.Abort()\r
97fa0ee9 2324 Utils.ClearDuplicatedInf()\r
52302d4d
LG
2325\r
2326 if ReturnCode == 0:\r
f0dc69e6
YZ
2327 try:\r
2328 MyBuild.LanuchPostbuild()\r
2329 Conclusion = "Done"\r
2330 except:\r
2331 Conclusion = "Failed"\r
52302d4d
LG
2332 elif ReturnCode == ABORT_ERROR:\r
2333 Conclusion = "Aborted"\r
2334 else:\r
2335 Conclusion = "Failed"\r
2336 FinishTime = time.time()\r
4234283c
LG
2337 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))\r
2338 BuildDurationStr = ""\r
2339 if BuildDuration.tm_yday > 1:\r
47fea6af 2340 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)\r
4234283c
LG
2341 else:\r
2342 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)\r
52302d4d 2343 if MyBuild != None:\r
09ae0f11
YL
2344 if not BuildError:\r
2345 MyBuild.BuildReport.GenerateReport(BuildDurationStr)\r
52302d4d
LG
2346 MyBuild.Db.Close()\r
2347 EdkLogger.SetLevel(EdkLogger.QUIET)\r
6780eef1
LG
2348 EdkLogger.quiet("\n- %s -" % Conclusion)\r
2349 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
4234283c 2350 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
52302d4d
LG
2351 return ReturnCode\r
2352\r
2353if __name__ == '__main__':\r
2354 r = Main()\r
2355 ## 0-127 is a safe return range, and 1 is a standard default error\r
2356 if r < 0 or r > 127: r = 1\r
2357 sys.exit(r)\r
2358\r