4 # Copyright (c) 2007 - 2018, 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 from Common
.DataType
import *
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
.BuildVersion
import gBUILD_VERSION
42 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
43 import FfsFileStatement
45 from struct
import unpack
47 ## Version and Copyright
48 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
49 __version__
= "%prog Version " + versionNumber
50 __copyright__
= "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."
52 ## Tool entrance method
54 # This method mainly dispatch specific methods per the command line options.
55 # If no error found, return zero value so the caller of this tool can know
56 # if it's executed successfully or not.
58 # @retval 0 Tool was successful
59 # @retval 1 Tool failed
63 Options
= myOptionParser()
70 EdkLogger
.Initialize()
72 if Options
.verbose
is not None:
73 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
74 GenFdsGlobalVariable
.VerboseMode
= True
76 if Options
.FixedAddress
is not None:
77 GenFdsGlobalVariable
.FixedLoadAddress
= True
79 if Options
.quiet
is not None:
80 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
81 if Options
.debug
is not None:
82 EdkLogger
.SetLevel(Options
.debug
+ 1)
83 GenFdsGlobalVariable
.DebugLevel
= Options
.debug
85 EdkLogger
.SetLevel(EdkLogger
.INFO
)
87 if (Options
.Workspace
is None):
88 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
89 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
90 elif not os
.path
.exists(Options
.Workspace
):
91 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
92 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
94 Workspace
= os
.path
.normcase(Options
.Workspace
)
95 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
96 if 'EDK_SOURCE' in os
.environ
.keys():
97 GenFdsGlobalVariable
.EdkSourceDir
= os
.path
.normcase(os
.environ
['EDK_SOURCE'])
99 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
100 if Options
.GenfdsMultiThread
:
101 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
102 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
104 # set multiple workspace
105 PackagesPath
= os
.getenv("PACKAGES_PATH")
106 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
108 if (Options
.filename
):
109 FdfFilename
= Options
.filename
110 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
112 if FdfFilename
[0:2] == '..':
113 FdfFilename
= os
.path
.realpath(FdfFilename
)
114 if not os
.path
.isabs(FdfFilename
):
115 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
116 if not os
.path
.exists(FdfFilename
):
117 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
119 GenFdsGlobalVariable
.FdfFile
= FdfFilename
120 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
122 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
124 if (Options
.BuildTarget
):
125 GenFdsGlobalVariable
.TargetName
= Options
.BuildTarget
127 if (Options
.ToolChain
):
128 GenFdsGlobalVariable
.ToolChainTag
= Options
.ToolChain
130 if (Options
.activePlatform
):
131 ActivePlatform
= Options
.activePlatform
132 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
134 if ActivePlatform
[0:2] == '..':
135 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
137 if not os
.path
.isabs (ActivePlatform
):
138 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
140 if not os
.path
.exists(ActivePlatform
) :
141 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
143 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
145 GlobalData
.BuildOptionPcd
= Options
.OptionPcd
if Options
.OptionPcd
else {}
146 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
148 if (Options
.ConfDirectory
):
149 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
150 ConfDirectoryPath
= os
.path
.normpath(Options
.ConfDirectory
)
151 if ConfDirectoryPath
.startswith('"'):
152 ConfDirectoryPath
= ConfDirectoryPath
[1:]
153 if ConfDirectoryPath
.endswith('"'):
154 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
155 if not os
.path
.isabs(ConfDirectoryPath
):
156 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
157 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
158 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
160 if "CONF_PATH" in os
.environ
.keys():
161 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
163 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
164 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
165 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
166 if not GlobalData
.gConfDirectory
:
167 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
168 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
169 if os
.path
.isfile(BuildConfigurationFile
) == True:
170 TargetTxt
= TargetTxtClassObject
.TargetTxtClassObject()
171 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
172 # if no build target given in command line, get it from target.txt
173 if not GenFdsGlobalVariable
.TargetName
:
174 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET
]
175 if len(BuildTargetList
) != 1:
176 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
177 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
179 # if no tool chain given in command line, get it from target.txt
180 if not GenFdsGlobalVariable
.ToolChainTag
:
181 ToolChainList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
182 if ToolChainList
is None or len(ToolChainList
) == 0:
183 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
184 if len(ToolChainList
) != 1:
185 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
186 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
188 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
190 #Set global flag for build mode
191 GlobalData
.gIgnoreSource
= Options
.IgnoreSources
194 for Pair
in Options
.Macros
:
195 if Pair
.startswith('"'):
197 if Pair
.endswith('"'):
199 List
= Pair
.split('=')
201 if not List
[1].strip():
202 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
203 if List
[0].strip() == "EFI_SOURCE":
204 GlobalData
.gEfiSource
= List
[1].strip()
205 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = GlobalData
.gEfiSource
207 elif List
[0].strip() == "EDK_SOURCE":
208 GlobalData
.gEdkSource
= List
[1].strip()
209 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = GlobalData
.gEdkSource
211 elif List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
212 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
214 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
216 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
217 os
.environ
["WORKSPACE"] = Workspace
219 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
220 if "TARGET" not in GlobalData
.gGlobalDefines
.keys():
221 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
222 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
.keys():
223 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
224 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
.keys():
225 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
227 """call Workspace build create database"""
228 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
229 BuildWorkSpace
= WorkspaceDatabase(GlobalData
.gDatabasePath
)
230 BuildWorkSpace
.InitDatabase()
233 # Get files real name in workspace dir
235 GlobalData
.gAllFiles
= DirCache(Workspace
)
236 GlobalData
.gWorkspace
= Workspace
238 if (Options
.archList
) :
239 ArchList
= Options
.archList
.split(',')
241 # EdkLogger.error("GenFds", OPTION_MISSING, "Missing build ARCH")
242 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON', Options
.BuildTarget
, Options
.ToolChain
].SupArchList
244 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON', Options
.BuildTarget
, Options
.ToolChain
].SupArchList
) & set(ArchList
)
245 if len(TargetArchList
) == 0:
246 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON'].SupArchList
)))
248 for Arch
in ArchList
:
249 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].OutputDirectory
)
250 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].PlatformName
252 if (Options
.outputDir
):
253 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(Options
.outputDir
)
254 if not os
.path
.isabs (OutputDirFromCommandLine
):
255 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
256 for Arch
in ArchList
:
257 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
259 for Arch
in ArchList
:
260 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
262 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
263 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
264 if OutputDir
[0:2] == '..':
265 OutputDir
= os
.path
.realpath(OutputDir
)
267 if OutputDir
[1] != ':':
268 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
270 if not os
.path
.exists(OutputDir
):
271 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
272 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
274 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
275 FdfParserObj
= FdfParser
.FdfParser(FdfFilename
)
276 FdfParserObj
.ParseFile()
278 if FdfParserObj
.CycleReferenceCheck():
279 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
281 if (Options
.uiFdName
) :
282 if Options
.uiFdName
.upper() in FdfParserObj
.Profile
.FdDict
.keys():
283 GenFds
.OnlyGenerateThisFd
= Options
.uiFdName
285 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
286 "No such an FD in FDF file: %s" % Options
.uiFdName
)
288 if (Options
.uiFvName
) :
289 if Options
.uiFvName
.upper() in FdfParserObj
.Profile
.FvDict
.keys():
290 GenFds
.OnlyGenerateThisFv
= Options
.uiFvName
292 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
293 "No such an FV in FDF file: %s" % Options
.uiFvName
)
295 if (Options
.uiCapName
) :
296 if Options
.uiCapName
.upper() in FdfParserObj
.Profile
.CapsuleDict
.keys():
297 GenFds
.OnlyGenerateThisCap
= Options
.uiCapName
299 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
300 "No such a Capsule in FDF file: %s" % Options
.uiCapName
)
302 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
303 if ArchList
is not None:
304 GenFdsGlobalVariable
.ArchList
= ArchList
306 # Dsc Build Data will handle Pcd Settings from CommandLine.
308 """Modify images from build output if the feature of loading driver at fixed address is on."""
309 if GenFdsGlobalVariable
.FixedLoadAddress
:
310 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
312 # Record the FV Region info that may specific in the FD
313 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
314 for Fv
in FdfParserObj
.Profile
.FvDict
:
315 FvObj
= FdfParserObj
.Profile
.FvDict
[Fv
]
316 for Fd
in FdfParserObj
.Profile
.FdDict
:
317 FdObj
= FdfParserObj
.Profile
.FdDict
[Fd
]
318 for RegionObj
in FdObj
.RegionList
:
319 if RegionObj
.RegionType
!= 'FV':
321 for RegionData
in RegionObj
.RegionDataList
:
322 if FvObj
.UiFvName
.upper() == RegionData
.upper():
323 if FvObj
.FvRegionInFD
:
324 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
325 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
327 FvObj
.FvRegionInFD
= RegionObj
.Size
328 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
331 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
333 """Generate GUID cross reference file"""
334 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
336 """Display FV space info."""
337 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
339 except FdfParser
.Warning, X
:
340 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
341 ReturnCode
= FORMAT_INVALID
342 except FatalError
, X
:
343 if Options
.debug
is not None:
345 EdkLogger
.quiet(traceback
.format_exc())
346 ReturnCode
= X
.args
[0]
352 "Tools code failure",
353 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
356 EdkLogger
.quiet(traceback
.format_exc())
357 ReturnCode
= CODE_ERROR
363 def SingleCheckCallback(option
, opt_str
, value
, parser
):
364 if option
not in gParamCheck
:
365 setattr(parser
.values
, option
.dest
, value
)
366 gParamCheck
.append(option
)
368 parser
.error("Option %s only allows one instance in command line!" % option
)
372 # Find location of tools to process data
374 # @param KeyStringList Filter for inputs of section generation
375 # @param CurrentArchList Arch list
376 # @param NameGuid The Guid name
378 def FindExtendTool(KeyStringList
, CurrentArchList
, NameGuid
):
379 ToolDb
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDatabase
380 # if user not specify filter, try to deduce it from global data.
381 if KeyStringList
is None or KeyStringList
== []:
382 Target
= GenFdsGlobalVariable
.TargetName
383 ToolChain
= GenFdsGlobalVariable
.ToolChainTag
384 if ToolChain
not in ToolDb
['TOOL_CHAIN_TAG']:
385 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain
)
386 KeyStringList
= [Target
+ '_' + ToolChain
+ '_' + CurrentArchList
[0]]
387 for Arch
in CurrentArchList
:
388 if Target
+ '_' + ToolChain
+ '_' + Arch
not in KeyStringList
:
389 KeyStringList
.append(Target
+ '_' + ToolChain
+ '_' + Arch
)
391 if GenFdsGlobalVariable
.GuidToolDefinition
:
392 if NameGuid
in GenFdsGlobalVariable
.GuidToolDefinition
.keys():
393 return GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
]
395 ToolDefinition
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDictionary
401 for ToolDef
in ToolDefinition
.items():
402 if NameGuid
.lower() == ToolDef
[1].lower() :
403 KeyList
= ToolDef
[0].split('_')
409 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
410 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
411 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
412 ToolPath
= ToolDefinition
.get(ToolPathKey
)
413 ToolOption
= ToolDefinition
.get(ToolOptionKey
)
414 if ToolPathTmp
is None:
415 ToolPathTmp
= ToolPath
417 if ToolPathTmp
!= ToolPath
:
418 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp
, ToolPath
))
421 for Arch
in CurrentArchList
:
422 Platform
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
423 # key is (ToolChainFamily, ToolChain, CodeBase)
424 for item
in Platform
.BuildOptions
:
425 if '_PATH' in item
[1] or '_FLAGS' in item
[1] or '_GUID' in item
[1]:
426 if not item
[0] or (item
[0] and GenFdsGlobalVariable
.ToolChainFamily
== item
[0]):
427 if item
[1] not in BuildOption
:
428 BuildOption
[item
[1]] = Platform
.BuildOptions
[item
]
430 ToolList
= [TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
, TAB_TOD_DEFINES_TARGET_ARCH
]
431 for Index
in range(2, -1, -1):
432 for Key
in dict(BuildOption
):
433 List
= Key
.split('_')
434 if List
[Index
] == '*':
435 for String
in ToolDb
[ToolList
[Index
]]:
436 if String
in [Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]:
438 NewKey
= '%s_%s_%s_%s_%s' % tuple(List
)
439 if NewKey
not in BuildOption
:
440 BuildOption
[NewKey
] = BuildOption
[Key
]
443 elif List
[Index
] not in ToolDb
[ToolList
[Index
]]:
447 for Op
in BuildOption
:
448 if NameGuid
== BuildOption
[Op
]:
449 KeyList
= Op
.split('_')
450 Key
= KeyList
[0] + '_' + KeyList
[1] +'_' + KeyList
[2]
451 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
452 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
453 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
454 if ToolPathKey
in BuildOption
.keys():
455 ToolPathTmp
= BuildOption
.get(ToolPathKey
)
456 if ToolOptionKey
in BuildOption
.keys():
457 ToolOption
= BuildOption
.get(ToolOptionKey
)
459 GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
] = (ToolPathTmp
, ToolOption
)
460 return ToolPathTmp
, ToolOption
462 ## Parse command line options
464 # Using standard Python module optparse to parse command line option of this tool.
466 # @retval Opt A optparse.Values object containing the parsed options
467 # @retval Args Target of build command
469 def myOptionParser():
470 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
471 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
472 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
473 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")
474 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
475 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
476 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
477 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
478 action
="callback", callback
=SingleCheckCallback
)
479 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
480 action
="callback", callback
=SingleCheckCallback
)
481 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
482 action
="callback", callback
=SingleCheckCallback
)
483 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
484 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
485 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
486 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
487 action
="callback", callback
=SingleCheckCallback
)
488 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
489 action
="callback", callback
=SingleCheckCallback
)
490 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
491 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
492 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
493 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
494 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
495 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
497 (Options
, args
) = Parser
.parse_args()
500 ## The class implementing the EDK2 flash image generation process
502 # This process includes:
503 # 1. Collect workspace information, includes platform and module information
504 # 2. Call methods of Fd class to generate FD
505 # 3. Call methods of Fv class to generate FV that not belong to FD
509 # FvName, FdName, CapName in FDF, Image file name
511 OnlyGenerateThisFd
= None
512 OnlyGenerateThisFv
= None
513 OnlyGenerateThisCap
= None
517 # @param OutputDir Output directory
518 # @param FdfParser FDF contents parser
519 # @param Workspace The directory of workspace
520 # @param ArchList The Arch list of platform
522 def GenFd (OutputDir
, FdfParser
, WorkSpace
, ArchList
):
523 GenFdsGlobalVariable
.SetDir ('', FdfParser
, WorkSpace
, ArchList
)
525 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
526 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
527 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.get(GenFds
.OnlyGenerateThisCap
.upper())
528 if CapsuleObj
is not None:
529 CapsuleObj
.GenCapsule()
532 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
533 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.get(GenFds
.OnlyGenerateThisFd
.upper())
534 if FdObj
is not None:
537 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
538 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
539 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
542 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
543 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
544 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.get(GenFds
.OnlyGenerateThisFv
.upper())
545 if FvObj
is not None:
546 Buffer
= StringIO
.StringIO()
547 FvObj
.AddToBuffer(Buffer
)
550 elif GenFds
.OnlyGenerateThisFv
is None:
551 for FvName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
552 Buffer
= StringIO
.StringIO('')
553 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[FvName
]
554 FvObj
.AddToBuffer(Buffer
)
557 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
558 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
559 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
560 for CapsuleName
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
561 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[CapsuleName
]
562 CapsuleObj
.GenCapsule()
564 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
565 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
566 for DriverName
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.keys():
567 OptRomObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
[DriverName
]
568 OptRomObj
.AddToBuffer(None)
570 def GenFfsMakefile(OutputDir
, FdfParser
, WorkSpace
, ArchList
, GlobalData
):
571 GenFdsGlobalVariable
.SetEnv(FdfParser
, WorkSpace
, ArchList
, GlobalData
)
572 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
573 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
574 FdObj
.GenFd(Flag
=True)
576 for FvName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
577 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[FvName
]
578 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
580 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
581 for DriverName
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.keys():
582 OptRomObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
[DriverName
]
583 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
585 return GenFdsGlobalVariable
.FfsCmdDict
589 # @param FvObj Whose block size to get
590 # @retval int Block size value
592 def GetFvBlockSize(FvObj
):
593 DefaultBlockSize
= 0x1
595 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
596 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
598 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
599 for ElementRegion
in ElementFd
.RegionList
:
600 if ElementRegion
.RegionType
== 'FV':
601 for ElementRegionData
in ElementRegion
.RegionDataList
:
602 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
603 if FvObj
.BlockSizeList
!= []:
604 return FvObj
.BlockSizeList
[0][0]
606 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
607 if FvObj
.BlockSizeList
!= []:
608 return FvObj
.BlockSizeList
[0][0]
609 return DefaultBlockSize
611 for ElementRegion
in FdObj
.RegionList
:
612 if ElementRegion
.RegionType
== 'FV':
613 for ElementRegionData
in ElementRegion
.RegionDataList
:
614 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
615 if FvObj
.BlockSizeList
!= []:
616 return FvObj
.BlockSizeList
[0][0]
618 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
619 return DefaultBlockSize
621 ## DisplayFvSpaceInfo()
623 # @param FvObj Whose block size to get
626 def DisplayFvSpaceInfo(FdfParser
):
630 for FvName
in FdfParser
.Profile
.FvDict
:
631 if len(FvName
) > MaxFvNameLength
:
632 MaxFvNameLength
= len(FvName
)
633 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
634 if os
.path
.exists(FvSpaceInfoFileName
):
635 FileLinesList
= linecache
.getlines(FvSpaceInfoFileName
)
642 for Line
in FileLinesList
:
643 NameValue
= Line
.split('=')
644 if len(NameValue
) == 2:
645 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
647 Total
= NameValue
[1].strip()
648 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
650 Used
= NameValue
[1].strip()
651 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
653 Free
= NameValue
[1].strip()
655 if TotalFound
and UsedFound
and FreeFound
:
656 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
658 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
659 for FvSpaceInfo
in FvSpaceInfoList
:
660 Name
= FvSpaceInfo
[0]
661 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
662 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
663 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
664 if UsedSizeValue
== TotalSizeValue
:
667 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
669 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
673 # @param BuildDb Database from build meta data files
674 # @param DscFile modules from dsc file will be preprocessed
677 def PreprocessImage(BuildDb
, DscFile
):
678 PcdDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
681 PcdObj
= PcdDict
[Key
]
682 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
683 PcdValue
= PcdObj
.DefaultValue
689 Int64PcdValue
= long(PcdValue
, 0)
690 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
694 if Int64PcdValue
> 0:
695 TopAddress
= Int64PcdValue
697 ModuleDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
698 for Key
in ModuleDict
:
699 ModuleObj
= BuildDb
.BuildObject
[Key
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
700 print ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
702 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
703 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
704 GuidXRefFile
= StringIO
.StringIO('')
708 for Arch
in ArchList
:
709 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
710 for ModuleFile
in PlatformDataBase
.Modules
:
711 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
712 if Module
in ModuleList
:
715 ModuleList
.append(Module
)
716 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
717 for key
, item
in Module
.Protocols
.items():
719 for key
, item
in Module
.Guids
.items():
721 for key
, item
in Module
.Ppis
.items():
723 for FvName
in FdfParserObj
.Profile
.FvDict
:
724 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
725 if not isinstance(FfsObj
, FfsFileStatement
.FileStatement
):
726 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
727 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
728 if FdfModule
in ModuleList
:
731 ModuleList
.append(FdfModule
)
732 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
733 for key
, item
in FdfModule
.Protocols
.items():
735 for key
, item
in FdfModule
.Guids
.items():
737 for key
, item
in FdfModule
.Ppis
.items():
740 FileStatementGuid
= FfsObj
.NameGuid
741 if FileStatementGuid
in FileGuidList
:
744 FileGuidList
.append(FileStatementGuid
)
746 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
747 FfsPath
= glob
.glob(os
.path
.join(FfsPath
, FileStatementGuid
) + '*')
750 if not os
.path
.exists(FfsPath
[0]):
753 ReFileEnds
= re
.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
754 FileList
= os
.listdir(FfsPath
[0])
755 for File
in FileList
:
756 Match
= ReFileEnds
.search(File
)
758 for Index
in range(1, 8):
759 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
760 MatchDict
[Match
.group(Index
)].append(File
)
761 elif Match
.group(Index
):
762 MatchDict
[Match
.group(Index
)] = [File
]
765 if '.ui' in MatchDict
:
766 for File
in MatchDict
['.ui']:
767 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
771 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
772 Name
= ''.join([chr(c
) for c
in TmpStr
[:-1]])
775 if 'fv.sec.txt' in MatchDict
:
776 FileList
= MatchDict
['fv.sec.txt']
777 elif '.pe32.txt' in MatchDict
:
778 FileList
= MatchDict
['.pe32.txt']
779 elif '.te.txt' in MatchDict
:
780 FileList
= MatchDict
['.te.txt']
781 elif '.pic.txt' in MatchDict
:
782 FileList
= MatchDict
['.pic.txt']
783 elif '.raw.txt' in MatchDict
:
784 FileList
= MatchDict
['.raw.txt']
785 elif '.ffs.txt' in MatchDict
:
786 FileList
= MatchDict
['.ffs.txt']
789 for File
in FileList
:
790 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
791 Name
.append((F
.read().split()[-1]))
795 Name
= ' '.join(Name
) if type(Name
) == type([]) else Name
796 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
798 # Append GUIDs, Protocols, and PPIs to the Xref file
799 GuidXRefFile
.write("\n")
800 for key
, item
in GuidDict
.items():
801 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
803 if GuidXRefFile
.getvalue():
804 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
805 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
806 elif os
.path
.exists(GuidXRefFileName
):
807 os
.remove(GuidXRefFileName
)
810 ##Define GenFd as static function
811 GenFd
= staticmethod(GenFd
)
812 GetFvBlockSize
= staticmethod(GetFvBlockSize
)
813 DisplayFvSpaceInfo
= staticmethod(DisplayFvSpaceInfo
)
814 PreprocessImage
= staticmethod(PreprocessImage
)
815 GenerateGuidXRefFile
= staticmethod(GenerateGuidXRefFile
)
817 if __name__
== '__main__':
819 ## 0-127 is a safe return range, and 1 is a standard default error
820 if r
< 0 or r
> 127: r
= 1