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