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