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