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 import RuleComplexFile
28 from EfiSection
import EfiSection
30 import Common
.TargetTxtClassObject
as TargetTxtClassObject
31 import Common
.ToolDefClassObject
as ToolDefClassObject
32 from Common
.DataType
import *
33 import Common
.GlobalData
as GlobalData
34 from Common
import EdkLogger
35 from Common
.String
import *
36 from Common
.Misc
import DirCache
, PathClass
37 from Common
.Misc
import SaveFileOnChange
38 from Common
.Misc
import ClearDuplicatedInf
39 from Common
.Misc
import GuidStructureStringToGuidString
40 from Common
.BuildVersion
import gBUILD_VERSION
41 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
42 import FfsFileStatement
44 from struct
import unpack
46 ## Version and Copyright
47 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
48 __version__
= "%prog Version " + versionNumber
49 __copyright__
= "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."
51 ## Tool entrance method
53 # This method mainly dispatch specific methods per the command line options.
54 # If no error found, return zero value so the caller of this tool can know
55 # if it's executed successfully or not.
57 # @retval 0 Tool was successful
58 # @retval 1 Tool failed
62 Options
= myOptionParser()
69 EdkLogger
.Initialize()
71 if Options
.verbose
is not None:
72 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
73 GenFdsGlobalVariable
.VerboseMode
= True
75 if Options
.FixedAddress
is not None:
76 GenFdsGlobalVariable
.FixedLoadAddress
= True
78 if Options
.quiet
is not None:
79 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
80 if Options
.debug
is not None:
81 EdkLogger
.SetLevel(Options
.debug
+ 1)
82 GenFdsGlobalVariable
.DebugLevel
= Options
.debug
84 EdkLogger
.SetLevel(EdkLogger
.INFO
)
86 if (Options
.Workspace
is None):
87 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
88 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
89 elif not os
.path
.exists(Options
.Workspace
):
90 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
91 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
93 Workspace
= os
.path
.normcase(Options
.Workspace
)
94 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
95 if 'EDK_SOURCE' in os
.environ
:
96 GenFdsGlobalVariable
.EdkSourceDir
= os
.path
.normcase(os
.environ
['EDK_SOURCE'])
98 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
99 if Options
.GenfdsMultiThread
:
100 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
101 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
103 # set multiple workspace
104 PackagesPath
= os
.getenv("PACKAGES_PATH")
105 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
107 if (Options
.filename
):
108 FdfFilename
= Options
.filename
109 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
111 if FdfFilename
[0:2] == '..':
112 FdfFilename
= os
.path
.realpath(FdfFilename
)
113 if not os
.path
.isabs(FdfFilename
):
114 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
115 if not os
.path
.exists(FdfFilename
):
116 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
118 GenFdsGlobalVariable
.FdfFile
= FdfFilename
119 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
121 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
123 if (Options
.BuildTarget
):
124 GenFdsGlobalVariable
.TargetName
= Options
.BuildTarget
126 if (Options
.ToolChain
):
127 GenFdsGlobalVariable
.ToolChainTag
= Options
.ToolChain
129 if (Options
.activePlatform
):
130 ActivePlatform
= Options
.activePlatform
131 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
133 if ActivePlatform
[0:2] == '..':
134 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
136 if not os
.path
.isabs (ActivePlatform
):
137 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
139 if not os
.path
.exists(ActivePlatform
) :
140 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
142 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
144 GlobalData
.BuildOptionPcd
= Options
.OptionPcd
if Options
.OptionPcd
else {}
145 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
147 if (Options
.ConfDirectory
):
148 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
149 ConfDirectoryPath
= os
.path
.normpath(Options
.ConfDirectory
)
150 if ConfDirectoryPath
.startswith('"'):
151 ConfDirectoryPath
= ConfDirectoryPath
[1:]
152 if ConfDirectoryPath
.endswith('"'):
153 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
154 if not os
.path
.isabs(ConfDirectoryPath
):
155 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
156 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
157 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
159 if "CONF_PATH" in os
.environ
:
160 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
162 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
163 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
164 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
165 if not GlobalData
.gConfDirectory
:
166 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
167 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
168 if os
.path
.isfile(BuildConfigurationFile
) == True:
169 TargetTxt
= TargetTxtClassObject
.TargetTxtClassObject()
170 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
171 # if no build target given in command line, get it from target.txt
172 if not GenFdsGlobalVariable
.TargetName
:
173 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET
]
174 if len(BuildTargetList
) != 1:
175 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
176 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
178 # if no tool chain given in command line, get it from target.txt
179 if not GenFdsGlobalVariable
.ToolChainTag
:
180 ToolChainList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
181 if ToolChainList
is None or len(ToolChainList
) == 0:
182 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
183 if len(ToolChainList
) != 1:
184 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
185 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
187 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
189 #Set global flag for build mode
190 GlobalData
.gIgnoreSource
= Options
.IgnoreSources
193 for Pair
in Options
.Macros
:
194 if Pair
.startswith('"'):
196 if Pair
.endswith('"'):
198 List
= Pair
.split('=')
200 if not List
[1].strip():
201 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
202 if List
[0].strip() == "EFI_SOURCE":
203 GlobalData
.gEfiSource
= List
[1].strip()
204 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = GlobalData
.gEfiSource
206 elif List
[0].strip() == "EDK_SOURCE":
207 GlobalData
.gEdkSource
= List
[1].strip()
208 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = GlobalData
.gEdkSource
210 elif List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
211 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
213 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
215 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
216 os
.environ
["WORKSPACE"] = Workspace
218 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
219 if "TARGET" not in GlobalData
.gGlobalDefines
:
220 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
221 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
:
222 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
223 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
:
224 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
226 """call Workspace build create database"""
227 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
228 BuildWorkSpace
= WorkspaceDatabase(GlobalData
.gDatabasePath
)
229 BuildWorkSpace
.InitDatabase()
232 # Get files real name in workspace dir
234 GlobalData
.gAllFiles
= DirCache(Workspace
)
235 GlobalData
.gWorkspace
= Workspace
237 if (Options
.archList
) :
238 ArchList
= Options
.archList
.split(',')
240 # EdkLogger.error("GenFds", OPTION_MISSING, "Missing build ARCH")
241 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, Options
.BuildTarget
, Options
.ToolChain
].SupArchList
243 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, Options
.BuildTarget
, Options
.ToolChain
].SupArchList
) & set(ArchList
)
244 if len(TargetArchList
) == 0:
245 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
].SupArchList
)))
247 for Arch
in ArchList
:
248 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].OutputDirectory
)
249 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].PlatformName
251 if (Options
.outputDir
):
252 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(Options
.outputDir
)
253 if not os
.path
.isabs (OutputDirFromCommandLine
):
254 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
255 for Arch
in ArchList
:
256 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
258 for Arch
in ArchList
:
259 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
261 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
262 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
263 if OutputDir
[0:2] == '..':
264 OutputDir
= os
.path
.realpath(OutputDir
)
266 if OutputDir
[1] != ':':
267 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
269 if not os
.path
.exists(OutputDir
):
270 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
271 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
273 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
274 FdfParserObj
= FdfParser
.FdfParser(FdfFilename
)
275 FdfParserObj
.ParseFile()
277 if FdfParserObj
.CycleReferenceCheck():
278 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
280 if (Options
.uiFdName
) :
281 if Options
.uiFdName
.upper() in FdfParserObj
.Profile
.FdDict
:
282 GenFds
.OnlyGenerateThisFd
= Options
.uiFdName
284 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
285 "No such an FD in FDF file: %s" % Options
.uiFdName
)
287 if (Options
.uiFvName
) :
288 if Options
.uiFvName
.upper() in FdfParserObj
.Profile
.FvDict
:
289 GenFds
.OnlyGenerateThisFv
= Options
.uiFvName
291 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
292 "No such an FV in FDF file: %s" % Options
.uiFvName
)
294 if (Options
.uiCapName
) :
295 if Options
.uiCapName
.upper() in FdfParserObj
.Profile
.CapsuleDict
:
296 GenFds
.OnlyGenerateThisCap
= Options
.uiCapName
298 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
299 "No such a Capsule in FDF file: %s" % Options
.uiCapName
)
301 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
302 if ArchList
is not None:
303 GenFdsGlobalVariable
.ArchList
= ArchList
305 # Dsc Build Data will handle Pcd Settings from CommandLine.
307 """Modify images from build output if the feature of loading driver at fixed address is on."""
308 if GenFdsGlobalVariable
.FixedLoadAddress
:
309 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
311 # Record the FV Region info that may specific in the FD
312 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
313 for Fv
in FdfParserObj
.Profile
.FvDict
:
314 FvObj
= FdfParserObj
.Profile
.FvDict
[Fv
]
315 for Fd
in FdfParserObj
.Profile
.FdDict
:
316 FdObj
= FdfParserObj
.Profile
.FdDict
[Fd
]
317 for RegionObj
in FdObj
.RegionList
:
318 if RegionObj
.RegionType
!= 'FV':
320 for RegionData
in RegionObj
.RegionDataList
:
321 if FvObj
.UiFvName
.upper() == RegionData
.upper():
322 if FvObj
.FvRegionInFD
:
323 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
324 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
326 FvObj
.FvRegionInFD
= RegionObj
.Size
327 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
330 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
332 """Generate GUID cross reference file"""
333 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
335 """Display FV space info."""
336 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
338 except FdfParser
.Warning, X
:
339 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
340 ReturnCode
= FORMAT_INVALID
341 except FatalError
, X
:
342 if Options
.debug
is not None:
344 EdkLogger
.quiet(traceback
.format_exc())
345 ReturnCode
= X
.args
[0]
351 "Tools code failure",
352 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
355 EdkLogger
.quiet(traceback
.format_exc())
356 ReturnCode
= CODE_ERROR
362 def SingleCheckCallback(option
, opt_str
, value
, parser
):
363 if option
not in gParamCheck
:
364 setattr(parser
.values
, option
.dest
, value
)
365 gParamCheck
.append(option
)
367 parser
.error("Option %s only allows one instance in command line!" % option
)
371 # Find location of tools to process data
373 # @param KeyStringList Filter for inputs of section generation
374 # @param CurrentArchList Arch list
375 # @param NameGuid The Guid name
377 def FindExtendTool(KeyStringList
, CurrentArchList
, NameGuid
):
378 ToolDb
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDatabase
379 # if user not specify filter, try to deduce it from global data.
380 if KeyStringList
is None or KeyStringList
== []:
381 Target
= GenFdsGlobalVariable
.TargetName
382 ToolChain
= GenFdsGlobalVariable
.ToolChainTag
383 if ToolChain
not in ToolDb
['TOOL_CHAIN_TAG']:
384 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain
)
385 KeyStringList
= [Target
+ '_' + ToolChain
+ '_' + CurrentArchList
[0]]
386 for Arch
in CurrentArchList
:
387 if Target
+ '_' + ToolChain
+ '_' + Arch
not in KeyStringList
:
388 KeyStringList
.append(Target
+ '_' + ToolChain
+ '_' + Arch
)
390 if GenFdsGlobalVariable
.GuidToolDefinition
:
391 if NameGuid
in GenFdsGlobalVariable
.GuidToolDefinition
:
392 return GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
]
394 ToolDefinition
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDictionary
400 for ToolDef
in ToolDefinition
.items():
401 if NameGuid
.lower() == ToolDef
[1].lower() :
402 KeyList
= ToolDef
[0].split('_')
408 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
409 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
410 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
411 ToolPath
= ToolDefinition
.get(ToolPathKey
)
412 ToolOption
= ToolDefinition
.get(ToolOptionKey
)
413 if ToolPathTmp
is None:
414 ToolPathTmp
= ToolPath
416 if ToolPathTmp
!= ToolPath
:
417 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp
, ToolPath
))
420 for Arch
in CurrentArchList
:
421 Platform
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
422 # key is (ToolChainFamily, ToolChain, CodeBase)
423 for item
in Platform
.BuildOptions
:
424 if '_PATH' in item
[1] or '_FLAGS' in item
[1] or '_GUID' in item
[1]:
425 if not item
[0] or (item
[0] and GenFdsGlobalVariable
.ToolChainFamily
== item
[0]):
426 if item
[1] not in BuildOption
:
427 BuildOption
[item
[1]] = Platform
.BuildOptions
[item
]
429 ToolList
= [TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
, TAB_TOD_DEFINES_TARGET_ARCH
]
430 for Index
in range(2, -1, -1):
431 for Key
in dict(BuildOption
):
432 List
= Key
.split('_')
433 if List
[Index
] == '*':
434 for String
in ToolDb
[ToolList
[Index
]]:
435 if String
in [Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]:
437 NewKey
= '%s_%s_%s_%s_%s' % tuple(List
)
438 if NewKey
not in BuildOption
:
439 BuildOption
[NewKey
] = BuildOption
[Key
]
442 elif List
[Index
] not in ToolDb
[ToolList
[Index
]]:
446 for Op
in BuildOption
:
447 if NameGuid
== BuildOption
[Op
]:
448 KeyList
= Op
.split('_')
449 Key
= KeyList
[0] + '_' + KeyList
[1] +'_' + KeyList
[2]
450 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
451 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
452 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
453 if ToolPathKey
in BuildOption
:
454 ToolPathTmp
= BuildOption
[ToolPathKey
]
455 if ToolOptionKey
in BuildOption
:
456 ToolOption
= BuildOption
[ToolOptionKey
]
458 GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
] = (ToolPathTmp
, ToolOption
)
459 return ToolPathTmp
, ToolOption
461 ## Parse command line options
463 # Using standard Python module optparse to parse command line option of this tool.
465 # @retval Opt A optparse.Values object containing the parsed options
466 # @retval Args Target of build command
468 def myOptionParser():
469 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
470 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
471 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
472 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")
473 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
474 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
475 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
476 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
477 action
="callback", callback
=SingleCheckCallback
)
478 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
479 action
="callback", callback
=SingleCheckCallback
)
480 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
481 action
="callback", callback
=SingleCheckCallback
)
482 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
483 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
484 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
485 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
486 action
="callback", callback
=SingleCheckCallback
)
487 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
488 action
="callback", callback
=SingleCheckCallback
)
489 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
490 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
491 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
492 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
493 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
494 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
496 (Options
, args
) = Parser
.parse_args()
499 ## The class implementing the EDK2 flash image generation process
501 # This process includes:
502 # 1. Collect workspace information, includes platform and module information
503 # 2. Call methods of Fd class to generate FD
504 # 3. Call methods of Fv class to generate FV that not belong to FD
508 # FvName, FdName, CapName in FDF, Image file name
510 OnlyGenerateThisFd
= None
511 OnlyGenerateThisFv
= None
512 OnlyGenerateThisCap
= None
516 # @param OutputDir Output directory
517 # @param FdfParser FDF contents parser
518 # @param Workspace The directory of workspace
519 # @param ArchList The Arch list of platform
521 def GenFd (OutputDir
, FdfParser
, WorkSpace
, ArchList
):
522 GenFdsGlobalVariable
.SetDir ('', FdfParser
, WorkSpace
, ArchList
)
524 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
525 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
:
526 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[GenFds
.OnlyGenerateThisCap
.upper()]
527 if CapsuleObj
is not None:
528 CapsuleObj
.GenCapsule()
531 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
532 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
533 if FdObj
is not None:
536 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
537 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
540 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
541 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
:
542 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[GenFds
.OnlyGenerateThisFv
.upper()]
543 if FvObj
is not None:
544 Buffer
= StringIO
.StringIO()
545 FvObj
.AddToBuffer(Buffer
)
548 elif GenFds
.OnlyGenerateThisFv
is None:
549 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
550 Buffer
= StringIO
.StringIO('')
551 FvObj
.AddToBuffer(Buffer
)
554 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
555 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
556 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
557 for CapsuleObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.values():
558 CapsuleObj
.GenCapsule()
560 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
561 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
562 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
563 OptRomObj
.AddToBuffer(None)
565 def GenFfsMakefile(OutputDir
, FdfParser
, WorkSpace
, ArchList
, GlobalData
):
566 GenFdsGlobalVariable
.SetEnv(FdfParser
, WorkSpace
, ArchList
, GlobalData
)
567 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
568 FdObj
.GenFd(Flag
=True)
570 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
571 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
573 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
574 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
575 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
577 return GenFdsGlobalVariable
.FfsCmdDict
581 # @param FvObj Whose block size to get
582 # @retval int Block size value
584 def GetFvBlockSize(FvObj
):
585 DefaultBlockSize
= 0x1
587 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
588 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
590 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
591 for ElementRegion
in ElementFd
.RegionList
:
592 if ElementRegion
.RegionType
== 'FV':
593 for ElementRegionData
in ElementRegion
.RegionDataList
:
594 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
595 if FvObj
.BlockSizeList
!= []:
596 return FvObj
.BlockSizeList
[0][0]
598 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
599 if FvObj
.BlockSizeList
!= []:
600 return FvObj
.BlockSizeList
[0][0]
601 return DefaultBlockSize
603 for ElementRegion
in FdObj
.RegionList
:
604 if ElementRegion
.RegionType
== 'FV':
605 for ElementRegionData
in ElementRegion
.RegionDataList
:
606 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
607 if FvObj
.BlockSizeList
!= []:
608 return FvObj
.BlockSizeList
[0][0]
610 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
611 return DefaultBlockSize
613 ## DisplayFvSpaceInfo()
615 # @param FvObj Whose block size to get
618 def DisplayFvSpaceInfo(FdfParser
):
622 for FvName
in FdfParser
.Profile
.FvDict
:
623 if len(FvName
) > MaxFvNameLength
:
624 MaxFvNameLength
= len(FvName
)
625 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
626 if os
.path
.exists(FvSpaceInfoFileName
):
627 FileLinesList
= linecache
.getlines(FvSpaceInfoFileName
)
634 for Line
in FileLinesList
:
635 NameValue
= Line
.split('=')
636 if len(NameValue
) == 2:
637 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
639 Total
= NameValue
[1].strip()
640 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
642 Used
= NameValue
[1].strip()
643 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
645 Free
= NameValue
[1].strip()
647 if TotalFound
and UsedFound
and FreeFound
:
648 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
650 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
651 for FvSpaceInfo
in FvSpaceInfoList
:
652 Name
= FvSpaceInfo
[0]
653 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
654 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
655 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
656 if UsedSizeValue
== TotalSizeValue
:
659 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
661 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
665 # @param BuildDb Database from build meta data files
666 # @param DscFile modules from dsc file will be preprocessed
669 def PreprocessImage(BuildDb
, DscFile
):
670 PcdDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
673 PcdObj
= PcdDict
[Key
]
674 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
675 PcdValue
= PcdObj
.DefaultValue
681 Int64PcdValue
= long(PcdValue
, 0)
682 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
686 if Int64PcdValue
> 0:
687 TopAddress
= Int64PcdValue
689 ModuleDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
690 for Key
in ModuleDict
:
691 ModuleObj
= BuildDb
.BuildObject
[Key
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
692 print ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
694 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
695 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
696 GuidXRefFile
= StringIO
.StringIO('')
700 for Arch
in ArchList
:
701 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
702 for ModuleFile
in PlatformDataBase
.Modules
:
703 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
704 if Module
in ModuleList
:
707 ModuleList
.append(Module
)
708 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
709 for key
, item
in Module
.Protocols
.items():
711 for key
, item
in Module
.Guids
.items():
713 for key
, item
in Module
.Ppis
.items():
715 for FvName
in FdfParserObj
.Profile
.FvDict
:
716 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
717 if not isinstance(FfsObj
, FfsFileStatement
.FileStatement
):
718 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
719 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
720 if FdfModule
in ModuleList
:
723 ModuleList
.append(FdfModule
)
724 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
725 for key
, item
in FdfModule
.Protocols
.items():
727 for key
, item
in FdfModule
.Guids
.items():
729 for key
, item
in FdfModule
.Ppis
.items():
732 FileStatementGuid
= FfsObj
.NameGuid
733 if FileStatementGuid
in FileGuidList
:
736 FileGuidList
.append(FileStatementGuid
)
738 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
739 FfsPath
= glob
.glob(os
.path
.join(FfsPath
, FileStatementGuid
) + '*')
742 if not os
.path
.exists(FfsPath
[0]):
745 ReFileEnds
= re
.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
746 FileList
= os
.listdir(FfsPath
[0])
747 for File
in FileList
:
748 Match
= ReFileEnds
.search(File
)
750 for Index
in range(1, 8):
751 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
752 MatchDict
[Match
.group(Index
)].append(File
)
753 elif Match
.group(Index
):
754 MatchDict
[Match
.group(Index
)] = [File
]
757 if '.ui' in MatchDict
:
758 for File
in MatchDict
['.ui']:
759 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
763 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
764 Name
= ''.join([chr(c
) for c
in TmpStr
[:-1]])
767 if 'fv.sec.txt' in MatchDict
:
768 FileList
= MatchDict
['fv.sec.txt']
769 elif '.pe32.txt' in MatchDict
:
770 FileList
= MatchDict
['.pe32.txt']
771 elif '.te.txt' in MatchDict
:
772 FileList
= MatchDict
['.te.txt']
773 elif '.pic.txt' in MatchDict
:
774 FileList
= MatchDict
['.pic.txt']
775 elif '.raw.txt' in MatchDict
:
776 FileList
= MatchDict
['.raw.txt']
777 elif '.ffs.txt' in MatchDict
:
778 FileList
= MatchDict
['.ffs.txt']
781 for File
in FileList
:
782 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
783 Name
.append((F
.read().split()[-1]))
787 Name
= ' '.join(Name
) if type(Name
) == type([]) else Name
788 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
790 # Append GUIDs, Protocols, and PPIs to the Xref file
791 GuidXRefFile
.write("\n")
792 for key
, item
in GuidDict
.items():
793 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
795 if GuidXRefFile
.getvalue():
796 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
797 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
798 elif os
.path
.exists(GuidXRefFileName
):
799 os
.remove(GuidXRefFileName
)
802 ##Define GenFd as static function
803 GenFd
= staticmethod(GenFd
)
804 GetFvBlockSize
= staticmethod(GetFvBlockSize
)
805 DisplayFvSpaceInfo
= staticmethod(DisplayFvSpaceInfo
)
806 PreprocessImage
= staticmethod(PreprocessImage
)
807 GenerateGuidXRefFile
= staticmethod(GenerateGuidXRefFile
)
809 if __name__
== '__main__':
811 ## 0-127 is a safe return range, and 1 is a standard default error
812 if r
< 0 or r
> 127: r
= 1