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