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