4 # Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the BSD License
8 # which accompanies this distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 from optparse
import OptionParser
20 import Common
.LongFilePathOs
as os
23 import Common
.BuildToolError
as BuildToolError
24 from GenFdsGlobalVariable
import GenFdsGlobalVariable
25 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
26 from Workspace
.BuildClassObject
import PcdClassObject
27 from Workspace
.BuildClassObject
import ModuleBuildClassObject
28 import RuleComplexFile
29 from EfiSection
import EfiSection
31 import Common
.TargetTxtClassObject
as TargetTxtClassObject
32 import Common
.ToolDefClassObject
as ToolDefClassObject
33 import Common
.DataType
34 import Common
.GlobalData
as GlobalData
35 from Common
import EdkLogger
36 from Common
.String
import *
37 from Common
.Misc
import DirCache
, PathClass
38 from Common
.Misc
import SaveFileOnChange
39 from Common
.Misc
import ClearDuplicatedInf
40 from Common
.Misc
import GuidStructureStringToGuidString
41 from Common
.Misc
import CheckPcdDatum
42 from Common
.BuildVersion
import gBUILD_VERSION
43 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
45 ## Version and Copyright
46 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
47 __version__
= "%prog Version " + versionNumber
48 __copyright__
= "Copyright (c) 2007 - 2016, Intel Corporation All rights reserved."
50 ## Tool entrance method
52 # This method mainly dispatch specific methods per the command line options.
53 # If no error found, return zero value so the caller of this tool can know
54 # if it's executed successfully or not.
56 # @retval 0 Tool was successful
57 # @retval 1 Tool failed
61 Options
= myOptionParser()
68 EdkLogger
.Initialize()
70 if Options
.verbose
!= None:
71 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
72 GenFdsGlobalVariable
.VerboseMode
= True
74 if Options
.FixedAddress
!= None:
75 GenFdsGlobalVariable
.FixedLoadAddress
= True
77 if Options
.quiet
!= None:
78 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
79 if Options
.debug
!= None:
80 EdkLogger
.SetLevel(Options
.debug
+ 1)
81 GenFdsGlobalVariable
.DebugLevel
= Options
.debug
83 EdkLogger
.SetLevel(EdkLogger
.INFO
)
85 if (Options
.Workspace
== None):
86 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
87 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
88 elif not os
.path
.exists(Options
.Workspace
):
89 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
90 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
92 Workspace
= os
.path
.normcase(Options
.Workspace
)
93 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
94 if 'EDK_SOURCE' in os
.environ
.keys():
95 GenFdsGlobalVariable
.EdkSourceDir
= os
.path
.normcase(os
.environ
['EDK_SOURCE'])
97 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
98 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
100 # set multiple workspace
101 PackagesPath
= os
.getenv("PACKAGES_PATH")
102 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
104 if (Options
.filename
):
105 FdfFilename
= Options
.filename
106 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
108 if FdfFilename
[0:2] == '..':
109 FdfFilename
= os
.path
.realpath(FdfFilename
)
110 if not os
.path
.isabs(FdfFilename
):
111 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
112 if not os
.path
.exists(FdfFilename
):
113 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
115 GenFdsGlobalVariable
.FdfFile
= FdfFilename
116 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
118 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
120 if (Options
.BuildTarget
):
121 GenFdsGlobalVariable
.TargetName
= Options
.BuildTarget
123 if (Options
.ToolChain
):
124 GenFdsGlobalVariable
.ToolChainTag
= Options
.ToolChain
126 if (Options
.activePlatform
):
127 ActivePlatform
= Options
.activePlatform
128 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
130 if ActivePlatform
[0:2] == '..':
131 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
133 if not os
.path
.isabs (ActivePlatform
):
134 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
136 if not os
.path
.exists(ActivePlatform
) :
137 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
139 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
141 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
143 if (Options
.ConfDirectory
):
144 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
145 ConfDirectoryPath
= os
.path
.normpath(Options
.ConfDirectory
)
146 if ConfDirectoryPath
.startswith('"'):
147 ConfDirectoryPath
= ConfDirectoryPath
[1:]
148 if ConfDirectoryPath
.endswith('"'):
149 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
150 if not os
.path
.isabs(ConfDirectoryPath
):
151 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
152 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
153 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
155 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
156 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
157 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
158 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
159 if os
.path
.isfile(BuildConfigurationFile
) == True:
160 TargetTxt
= TargetTxtClassObject
.TargetTxtClassObject()
161 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
162 # if no build target given in command line, get it from target.txt
163 if not GenFdsGlobalVariable
.TargetName
:
164 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET
]
165 if len(BuildTargetList
) != 1:
166 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
167 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
169 # if no tool chain given in command line, get it from target.txt
170 if not GenFdsGlobalVariable
.ToolChainTag
:
171 ToolChainList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
172 if ToolChainList
== None or len(ToolChainList
) == 0:
173 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
174 if len(ToolChainList
) != 1:
175 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
176 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
178 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
180 #Set global flag for build mode
181 GlobalData
.gIgnoreSource
= Options
.IgnoreSources
184 for Pair
in Options
.Macros
:
185 if Pair
.startswith('"'):
187 if Pair
.endswith('"'):
189 List
= Pair
.split('=')
191 if not List
[1].strip():
192 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
193 if List
[0].strip() == "EFI_SOURCE":
194 GlobalData
.gEfiSource
= List
[1].strip()
195 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = GlobalData
.gEfiSource
197 elif List
[0].strip() == "EDK_SOURCE":
198 GlobalData
.gEdkSource
= List
[1].strip()
199 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = GlobalData
.gEdkSource
201 elif List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
202 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
204 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
206 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
207 os
.environ
["WORKSPACE"] = Workspace
209 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
210 if "TARGET" not in GlobalData
.gGlobalDefines
.keys():
211 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
212 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
.keys():
213 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
214 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
.keys():
215 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
217 """call Workspace build create database"""
218 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
219 BuildWorkSpace
= WorkspaceDatabase(GlobalData
.gDatabasePath
)
220 BuildWorkSpace
.InitDatabase()
223 # Get files real name in workspace dir
225 GlobalData
.gAllFiles
= DirCache(Workspace
)
226 GlobalData
.gWorkspace
= Workspace
228 if (Options
.archList
) :
229 ArchList
= Options
.archList
.split(',')
231 # EdkLogger.error("GenFds", OPTION_MISSING, "Missing build ARCH")
232 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON', Options
.BuildTarget
, Options
.ToolChain
].SupArchList
234 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON', Options
.BuildTarget
, Options
.ToolChain
].SupArchList
) & set(ArchList
)
235 if len(TargetArchList
) == 0:
236 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON'].SupArchList
)))
238 for Arch
in ArchList
:
239 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].OutputDirectory
)
240 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].PlatformName
242 if (Options
.outputDir
):
243 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(Options
.outputDir
)
244 if not os
.path
.isabs (OutputDirFromCommandLine
):
245 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
246 for Arch
in ArchList
:
247 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
249 for Arch
in ArchList
:
250 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
252 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
253 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
254 if OutputDir
[0:2] == '..':
255 OutputDir
= os
.path
.realpath(OutputDir
)
257 if OutputDir
[1] != ':':
258 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
260 if not os
.path
.exists(OutputDir
):
261 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
262 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
264 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
265 FdfParserObj
= FdfParser
.FdfParser(FdfFilename
)
266 FdfParserObj
.ParseFile()
268 if FdfParserObj
.CycleReferenceCheck():
269 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
271 if (Options
.uiFdName
) :
272 if Options
.uiFdName
.upper() in FdfParserObj
.Profile
.FdDict
.keys():
273 GenFds
.OnlyGenerateThisFd
= Options
.uiFdName
275 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
276 "No such an FD in FDF file: %s" % Options
.uiFdName
)
278 if (Options
.uiFvName
) :
279 if Options
.uiFvName
.upper() in FdfParserObj
.Profile
.FvDict
.keys():
280 GenFds
.OnlyGenerateThisFv
= Options
.uiFvName
282 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
283 "No such an FV in FDF file: %s" % Options
.uiFvName
)
285 if (Options
.uiCapName
) :
286 if Options
.uiCapName
.upper() in FdfParserObj
.Profile
.CapsuleDict
.keys():
287 GenFds
.OnlyGenerateThisCap
= Options
.uiCapName
289 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
290 "No such a Capsule in FDF file: %s" % Options
.uiCapName
)
292 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
294 GenFdsGlobalVariable
.ArchList
= ArchList
296 if Options
.OptionPcd
:
297 GlobalData
.BuildOptionPcd
= Options
.OptionPcd
298 CheckBuildOptionPcd()
300 """Modify images from build output if the feature of loading driver at fixed address is on."""
301 if GenFdsGlobalVariable
.FixedLoadAddress
:
302 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
304 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
306 """Generate GUID cross reference file"""
307 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
)
309 """Display FV space info."""
310 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
312 except FdfParser
.Warning, X
:
313 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
314 ReturnCode
= FORMAT_INVALID
315 except FatalError
, X
:
316 if Options
.debug
!= None:
318 EdkLogger
.quiet(traceback
.format_exc())
319 ReturnCode
= X
.args
[0]
325 "Tools code failure",
326 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
329 EdkLogger
.quiet(traceback
.format_exc())
330 ReturnCode
= CODE_ERROR
336 def SingleCheckCallback(option
, opt_str
, value
, parser
):
337 if option
not in gParamCheck
:
338 setattr(parser
.values
, option
.dest
, value
)
339 gParamCheck
.append(option
)
341 parser
.error("Option %s only allows one instance in command line!" % option
)
343 def CheckBuildOptionPcd():
344 for Arch
in GenFdsGlobalVariable
.ArchList
:
345 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
346 for i
, pcd
in enumerate(GlobalData
.BuildOptionPcd
):
347 if type(pcd
) is tuple:
349 (pcdname
, pcdvalue
) = pcd
.split('=')
351 EdkLogger
.error('GenFds', OPTION_MISSING
, "No Value specified for the PCD %s." % (pcdname
))
353 (TokenSpaceGuidCName
, TokenCName
) = pcdname
.split('.')
357 TokenSpaceGuidCName
= ''
358 HasTokenSpace
= False
359 TokenSpaceGuidCNameList
= []
363 for package
in PkgList
:
364 for key
in package
.Pcds
:
365 PcdItem
= package
.Pcds
[key
]
367 if (PcdItem
.TokenCName
, PcdItem
.TokenSpaceGuidCName
) == (TokenCName
, TokenSpaceGuidCName
):
368 PcdDatumType
= PcdItem
.DatumType
369 NewValue
= BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, pcdvalue
)
372 if PcdItem
.TokenCName
== TokenCName
:
373 if not PcdItem
.TokenSpaceGuidCName
in TokenSpaceGuidCNameList
:
374 if len (TokenSpaceGuidCNameList
) < 1:
375 TokenSpaceGuidCNameList
.append(PcdItem
.TokenSpaceGuidCName
)
376 PcdDatumType
= PcdItem
.DatumType
377 TokenSpaceGuidCName
= PcdItem
.TokenSpaceGuidCName
378 NewValue
= BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, pcdvalue
)
383 PCD_VALIDATION_INFO_ERROR
,
384 "The Pcd %s is found under multiple different TokenSpaceGuid: %s and %s." % (TokenCName
, PcdItem
.TokenSpaceGuidCName
, TokenSpaceGuidCNameList
[0])
387 GlobalData
.BuildOptionPcd
[i
] = (TokenSpaceGuidCName
, TokenCName
, NewValue
)
389 def BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, Value
):
390 if PcdDatumType
== 'VOID*':
391 if Value
.startswith('L'):
393 EdkLogger
.error('GenFds', OPTION_VALUE_INVALID
, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", B"{...}"')
394 Value
= Value
[0] + '"' + Value
[1:] + '"'
395 elif Value
.startswith('B'):
397 EdkLogger
.error('GenFds', OPTION_VALUE_INVALID
, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", B"{...}"')
401 EdkLogger
.error('GenFds', OPTION_VALUE_INVALID
, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", B"{...}"')
402 Value
= '"' + Value
+ '"'
404 IsValid
, Cause
= CheckPcdDatum(PcdDatumType
, Value
)
406 EdkLogger
.error('build', FORMAT_INVALID
, Cause
, ExtraData
="%s.%s" % (TokenSpaceGuidCName
, TokenCName
))
407 if PcdDatumType
== 'BOOLEAN':
408 Value
= Value
.upper()
409 if Value
== 'TRUE' or Value
== '1':
411 elif Value
== 'FALSE' or Value
== '0':
416 ## Parse command line options
418 # Using standard Python module optparse to parse command line option of this tool.
420 # @retval Opt A optparse.Values object containing the parsed options
421 # @retval Args Target of build command
423 def myOptionParser():
424 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
425 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
426 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
427 Parser
.add_option("-a", "--arch", dest
="archList", help="comma separated list containing one or more of: IA32, X64, IPF, ARM, AARCH64 or EBC which should be built, overrides target.txt?s TARGET_ARCH")
428 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
429 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
430 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
431 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
432 action
="callback", callback
=SingleCheckCallback
)
433 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
434 action
="callback", callback
=SingleCheckCallback
)
435 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
436 action
="callback", callback
=SingleCheckCallback
)
437 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
438 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
439 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
440 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
441 action
="callback", callback
=SingleCheckCallback
)
442 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
443 action
="callback", callback
=SingleCheckCallback
)
444 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
445 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
446 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
447 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
448 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
450 (Options
, args
) = Parser
.parse_args()
453 ## The class implementing the EDK2 flash image generation process
455 # This process includes:
456 # 1. Collect workspace information, includes platform and module information
457 # 2. Call methods of Fd class to generate FD
458 # 3. Call methods of Fv class to generate FV that not belong to FD
462 # FvName, FdName, CapName in FDF, Image file name
464 OnlyGenerateThisFd
= None
465 OnlyGenerateThisFv
= None
466 OnlyGenerateThisCap
= None
470 # @param OutputDir Output directory
471 # @param FdfParser FDF contents parser
472 # @param Workspace The directory of workspace
473 # @param ArchList The Arch list of platform
475 def GenFd (OutputDir
, FdfParser
, WorkSpace
, ArchList
):
476 GenFdsGlobalVariable
.SetDir ('', FdfParser
, WorkSpace
, ArchList
)
478 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
479 if GenFds
.OnlyGenerateThisCap
!= None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
480 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.get(GenFds
.OnlyGenerateThisCap
.upper())
481 if CapsuleObj
!= None:
482 CapsuleObj
.GenCapsule()
485 if GenFds
.OnlyGenerateThisFd
!= None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
486 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.get(GenFds
.OnlyGenerateThisFd
.upper())
490 elif GenFds
.OnlyGenerateThisFd
== None and GenFds
.OnlyGenerateThisFv
== None:
491 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
492 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
495 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
496 if GenFds
.OnlyGenerateThisFv
!= None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
497 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.get(GenFds
.OnlyGenerateThisFv
.upper())
499 Buffer
= StringIO
.StringIO()
500 FvObj
.AddToBuffer(Buffer
)
503 elif GenFds
.OnlyGenerateThisFv
== None:
504 for FvName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
505 Buffer
= StringIO
.StringIO('')
506 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[FvName
]
507 FvObj
.AddToBuffer(Buffer
)
510 if GenFds
.OnlyGenerateThisFv
== None and GenFds
.OnlyGenerateThisFd
== None and GenFds
.OnlyGenerateThisCap
== None:
511 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
512 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
513 for CapsuleName
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
514 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[CapsuleName
]
515 CapsuleObj
.GenCapsule()
517 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
518 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
519 for DriverName
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.keys():
520 OptRomObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
[DriverName
]
521 OptRomObj
.AddToBuffer(None)
525 # @param FvObj Whose block size to get
526 # @retval int Block size value
528 def GetFvBlockSize(FvObj
):
529 DefaultBlockSize
= 0x1
531 if GenFds
.OnlyGenerateThisFd
!= None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
532 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
534 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
535 for ElementRegion
in ElementFd
.RegionList
:
536 if ElementRegion
.RegionType
== 'FV':
537 for ElementRegionData
in ElementRegion
.RegionDataList
:
538 if ElementRegionData
!= None and ElementRegionData
.upper() == FvObj
.UiFvName
:
539 if FvObj
.BlockSizeList
!= []:
540 return FvObj
.BlockSizeList
[0][0]
542 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
543 if FvObj
.BlockSizeList
!= []:
544 return FvObj
.BlockSizeList
[0][0]
545 return DefaultBlockSize
547 for ElementRegion
in FdObj
.RegionList
:
548 if ElementRegion
.RegionType
== 'FV':
549 for ElementRegionData
in ElementRegion
.RegionDataList
:
550 if ElementRegionData
!= None and ElementRegionData
.upper() == FvObj
.UiFvName
:
551 if FvObj
.BlockSizeList
!= []:
552 return FvObj
.BlockSizeList
[0][0]
554 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
555 return DefaultBlockSize
557 ## DisplayFvSpaceInfo()
559 # @param FvObj Whose block size to get
562 def DisplayFvSpaceInfo(FdfParser
):
566 for FvName
in FdfParser
.Profile
.FvDict
:
567 if len(FvName
) > MaxFvNameLength
:
568 MaxFvNameLength
= len(FvName
)
569 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
570 if os
.path
.exists(FvSpaceInfoFileName
):
571 FileLinesList
= linecache
.getlines(FvSpaceInfoFileName
)
578 for Line
in FileLinesList
:
579 NameValue
= Line
.split('=')
580 if len(NameValue
) == 2:
581 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
583 Total
= NameValue
[1].strip()
584 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
586 Used
= NameValue
[1].strip()
587 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
589 Free
= NameValue
[1].strip()
591 if TotalFound
and UsedFound
and FreeFound
:
592 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
594 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
595 for FvSpaceInfo
in FvSpaceInfoList
:
596 Name
= FvSpaceInfo
[0]
597 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
598 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
599 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
600 if UsedSizeValue
== TotalSizeValue
:
603 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
605 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
609 # @param BuildDb Database from build meta data files
610 # @param DscFile modules from dsc file will be preprocessed
613 def PreprocessImage(BuildDb
, DscFile
):
614 PcdDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
617 PcdObj
= PcdDict
[Key
]
618 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
619 PcdValue
= PcdObj
.DefaultValue
625 Int64PcdValue
= long(PcdValue
, 0)
626 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
630 if Int64PcdValue
> 0:
631 TopAddress
= Int64PcdValue
633 ModuleDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
634 for Key
in ModuleDict
:
635 ModuleObj
= BuildDb
.BuildObject
[Key
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
636 print ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
638 def GenerateGuidXRefFile(BuildDb
, ArchList
):
639 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
640 GuidXRefFile
= StringIO
.StringIO('')
642 for Arch
in ArchList
:
643 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
644 for ModuleFile
in PlatformDataBase
.Modules
:
645 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
646 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
647 for key
, item
in Module
.Protocols
.items():
649 for key
, item
in Module
.Guids
.items():
651 for key
, item
in Module
.Ppis
.items():
653 # Append GUIDs, Protocols, and PPIs to the Xref file
654 GuidXRefFile
.write("\n")
655 for key
, item
in GuidDict
.items():
656 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
658 if GuidXRefFile
.getvalue():
659 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
660 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
661 elif os
.path
.exists(GuidXRefFileName
):
662 os
.remove(GuidXRefFileName
)
665 ##Define GenFd as static function
666 GenFd
= staticmethod(GenFd
)
667 GetFvBlockSize
= staticmethod(GetFvBlockSize
)
668 DisplayFvSpaceInfo
= staticmethod(DisplayFvSpaceInfo
)
669 PreprocessImage
= staticmethod(PreprocessImage
)
670 GenerateGuidXRefFile
= staticmethod(GenerateGuidXRefFile
)
672 if __name__
== '__main__':
674 ## 0-127 is a safe return range, and 1 is a standard default error
675 if r
< 0 or r
> 127: r
= 1