4 # Copyright (c) 2007 - 2017, 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
.Misc
import CheckPcdDatum
42 from Common
.Misc
import BuildOptionPcdValueFormat
43 from Common
.BuildVersion
import gBUILD_VERSION
44 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
45 import FfsFileStatement
47 from struct
import unpack
49 ## Version and Copyright
50 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
51 __version__
= "%prog Version " + versionNumber
52 __copyright__
= "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."
54 ## Tool entrance method
56 # This method mainly dispatch specific methods per the command line options.
57 # If no error found, return zero value so the caller of this tool can know
58 # if it's executed successfully or not.
60 # @retval 0 Tool was successful
61 # @retval 1 Tool failed
65 Options
= myOptionParser()
72 EdkLogger
.Initialize()
74 if Options
.verbose
!= None:
75 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
76 GenFdsGlobalVariable
.VerboseMode
= True
78 if Options
.FixedAddress
!= None:
79 GenFdsGlobalVariable
.FixedLoadAddress
= True
81 if Options
.quiet
!= None:
82 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
83 if Options
.debug
!= None:
84 EdkLogger
.SetLevel(Options
.debug
+ 1)
85 GenFdsGlobalVariable
.DebugLevel
= Options
.debug
87 EdkLogger
.SetLevel(EdkLogger
.INFO
)
89 if (Options
.Workspace
== None):
90 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
91 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
92 elif not os
.path
.exists(Options
.Workspace
):
93 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
94 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
96 Workspace
= os
.path
.normcase(Options
.Workspace
)
97 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
98 if 'EDK_SOURCE' in os
.environ
.keys():
99 GenFdsGlobalVariable
.EdkSourceDir
= os
.path
.normcase(os
.environ
['EDK_SOURCE'])
101 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
102 if Options
.GenfdsMultiThread
:
103 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
104 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
106 # set multiple workspace
107 PackagesPath
= os
.getenv("PACKAGES_PATH")
108 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
110 if (Options
.filename
):
111 FdfFilename
= Options
.filename
112 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
114 if FdfFilename
[0:2] == '..':
115 FdfFilename
= os
.path
.realpath(FdfFilename
)
116 if not os
.path
.isabs(FdfFilename
):
117 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
118 if not os
.path
.exists(FdfFilename
):
119 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
121 GenFdsGlobalVariable
.FdfFile
= FdfFilename
122 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
124 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
126 if (Options
.BuildTarget
):
127 GenFdsGlobalVariable
.TargetName
= Options
.BuildTarget
129 if (Options
.ToolChain
):
130 GenFdsGlobalVariable
.ToolChainTag
= Options
.ToolChain
132 if (Options
.activePlatform
):
133 ActivePlatform
= Options
.activePlatform
134 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
136 if ActivePlatform
[0:2] == '..':
137 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
139 if not os
.path
.isabs (ActivePlatform
):
140 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
142 if not os
.path
.exists(ActivePlatform
) :
143 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
145 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
147 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
149 if (Options
.ConfDirectory
):
150 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
151 ConfDirectoryPath
= os
.path
.normpath(Options
.ConfDirectory
)
152 if ConfDirectoryPath
.startswith('"'):
153 ConfDirectoryPath
= ConfDirectoryPath
[1:]
154 if ConfDirectoryPath
.endswith('"'):
155 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
156 if not os
.path
.isabs(ConfDirectoryPath
):
157 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
158 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
159 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
161 if "CONF_PATH" in os
.environ
.keys():
162 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
164 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
165 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
166 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
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
== 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
.keys():
220 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
221 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
.keys():
222 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
223 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
.keys():
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
, 'COMMON', Options
.BuildTarget
, Options
.ToolChain
].SupArchList
243 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, '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
, '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
.keys():
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
.keys():
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
.keys():
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
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
)
329 GlobalData
.BuildOptionPcd
= Options
.OptionPcd
if Options
.OptionPcd
else {}
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
!= 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
)
370 def CheckBuildOptionPcd():
371 for Arch
in GenFdsGlobalVariable
.ArchList
:
372 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
373 for i
, pcd
in enumerate(GlobalData
.BuildOptionPcd
):
374 if type(pcd
) is tuple:
376 (pcdname
, pcdvalue
) = pcd
.split('=')
378 EdkLogger
.error('GenFds', OPTION_MISSING
, "No Value specified for the PCD %s." % (pcdname
))
380 (TokenSpaceGuidCName
, TokenCName
) = pcdname
.split('.')
384 TokenSpaceGuidCName
= ''
385 HasTokenSpace
= False
386 TokenSpaceGuidCNameList
= []
390 for package
in PkgList
:
391 for key
in package
.Pcds
:
392 PcdItem
= package
.Pcds
[key
]
394 if (PcdItem
.TokenCName
, PcdItem
.TokenSpaceGuidCName
) == (TokenCName
, TokenSpaceGuidCName
):
395 PcdDatumType
= PcdItem
.DatumType
396 NewValue
= BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, pcdvalue
)
399 if PcdItem
.TokenCName
== TokenCName
:
400 if not PcdItem
.TokenSpaceGuidCName
in TokenSpaceGuidCNameList
:
401 if len (TokenSpaceGuidCNameList
) < 1:
402 TokenSpaceGuidCNameList
.append(PcdItem
.TokenSpaceGuidCName
)
403 PcdDatumType
= PcdItem
.DatumType
404 TokenSpaceGuidCName
= PcdItem
.TokenSpaceGuidCName
405 NewValue
= BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, pcdvalue
)
410 PCD_VALIDATION_INFO_ERROR
,
411 "The Pcd %s is found under multiple different TokenSpaceGuid: %s and %s." % (TokenCName
, PcdItem
.TokenSpaceGuidCName
, TokenSpaceGuidCNameList
[0])
414 GlobalData
.BuildOptionPcd
[i
] = (TokenSpaceGuidCName
, TokenCName
, NewValue
)
419 # Find location of tools to process data
421 # @param KeyStringList Filter for inputs of section generation
422 # @param CurrentArchList Arch list
423 # @param NameGuid The Guid name
425 def FindExtendTool(KeyStringList
, CurrentArchList
, NameGuid
):
426 ToolDb
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDatabase
427 # if user not specify filter, try to deduce it from global data.
428 if KeyStringList
== None or KeyStringList
== []:
429 Target
= GenFdsGlobalVariable
.TargetName
430 ToolChain
= GenFdsGlobalVariable
.ToolChainTag
431 if ToolChain
not in ToolDb
['TOOL_CHAIN_TAG']:
432 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain
)
433 KeyStringList
= [Target
+ '_' + ToolChain
+ '_' + CurrentArchList
[0]]
434 for Arch
in CurrentArchList
:
435 if Target
+ '_' + ToolChain
+ '_' + Arch
not in KeyStringList
:
436 KeyStringList
.append(Target
+ '_' + ToolChain
+ '_' + Arch
)
438 if GenFdsGlobalVariable
.GuidToolDefinition
:
439 if NameGuid
in GenFdsGlobalVariable
.GuidToolDefinition
.keys():
440 return GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
]
442 ToolDefinition
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDictionary
448 for ToolDef
in ToolDefinition
.items():
449 if NameGuid
== ToolDef
[1]:
450 KeyList
= ToolDef
[0].split('_')
456 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
457 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
458 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
459 ToolPath
= ToolDefinition
.get(ToolPathKey
)
460 ToolOption
= ToolDefinition
.get(ToolOptionKey
)
461 if ToolPathTmp
== None:
462 ToolPathTmp
= ToolPath
464 if ToolPathTmp
!= ToolPath
:
465 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp
, ToolPath
))
468 for Arch
in CurrentArchList
:
469 Platform
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
470 # key is (ToolChainFamily, ToolChain, CodeBase)
471 for item
in Platform
.BuildOptions
:
472 if '_PATH' in item
[1] or '_FLAGS' in item
[1] or '_GUID' in item
[1]:
473 if not item
[0] or (item
[0] and GenFdsGlobalVariable
.ToolChainFamily
== item
[0]):
474 if item
[1] not in BuildOption
:
475 BuildOption
[item
[1]] = Platform
.BuildOptions
[item
]
477 ToolList
= [TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
, TAB_TOD_DEFINES_TARGET_ARCH
]
478 for Index
in range(2, -1, -1):
479 for Key
in dict(BuildOption
):
480 List
= Key
.split('_')
481 if List
[Index
] == '*':
482 for String
in ToolDb
[ToolList
[Index
]]:
483 if String
in [Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]:
485 NewKey
= '%s_%s_%s_%s_%s' % tuple(List
)
486 if NewKey
not in BuildOption
:
487 BuildOption
[NewKey
] = BuildOption
[Key
]
490 elif List
[Index
] not in ToolDb
[ToolList
[Index
]]:
494 for Op
in BuildOption
:
495 if NameGuid
== BuildOption
[Op
]:
496 KeyList
= Op
.split('_')
497 Key
= KeyList
[0] + '_' + KeyList
[1] +'_' + KeyList
[2]
498 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
499 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
500 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
501 if ToolPathKey
in BuildOption
.keys():
502 ToolPathTmp
= BuildOption
.get(ToolPathKey
)
503 if ToolOptionKey
in BuildOption
.keys():
504 ToolOption
= BuildOption
.get(ToolOptionKey
)
506 GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
] = (ToolPathTmp
, ToolOption
)
507 return ToolPathTmp
, ToolOption
509 ## Parse command line options
511 # Using standard Python module optparse to parse command line option of this tool.
513 # @retval Opt A optparse.Values object containing the parsed options
514 # @retval Args Target of build command
516 def myOptionParser():
517 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
518 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
519 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
520 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")
521 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
522 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
523 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
524 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
525 action
="callback", callback
=SingleCheckCallback
)
526 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
527 action
="callback", callback
=SingleCheckCallback
)
528 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
529 action
="callback", callback
=SingleCheckCallback
)
530 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
531 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
532 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
533 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
534 action
="callback", callback
=SingleCheckCallback
)
535 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
536 action
="callback", callback
=SingleCheckCallback
)
537 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
538 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
539 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
540 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
541 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
542 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
544 (Options
, args
) = Parser
.parse_args()
547 ## The class implementing the EDK2 flash image generation process
549 # This process includes:
550 # 1. Collect workspace information, includes platform and module information
551 # 2. Call methods of Fd class to generate FD
552 # 3. Call methods of Fv class to generate FV that not belong to FD
556 # FvName, FdName, CapName in FDF, Image file name
558 OnlyGenerateThisFd
= None
559 OnlyGenerateThisFv
= None
560 OnlyGenerateThisCap
= None
564 # @param OutputDir Output directory
565 # @param FdfParser FDF contents parser
566 # @param Workspace The directory of workspace
567 # @param ArchList The Arch list of platform
569 def GenFd (OutputDir
, FdfParser
, WorkSpace
, ArchList
):
570 GenFdsGlobalVariable
.SetDir ('', FdfParser
, WorkSpace
, ArchList
)
572 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
573 if GenFds
.OnlyGenerateThisCap
!= None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
574 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.get(GenFds
.OnlyGenerateThisCap
.upper())
575 if CapsuleObj
!= None:
576 CapsuleObj
.GenCapsule()
579 if GenFds
.OnlyGenerateThisFd
!= None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
580 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.get(GenFds
.OnlyGenerateThisFd
.upper())
584 elif GenFds
.OnlyGenerateThisFd
== None and GenFds
.OnlyGenerateThisFv
== None:
585 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
586 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
589 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
590 if GenFds
.OnlyGenerateThisFv
!= None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
591 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.get(GenFds
.OnlyGenerateThisFv
.upper())
593 Buffer
= StringIO
.StringIO()
594 FvObj
.AddToBuffer(Buffer
)
597 elif GenFds
.OnlyGenerateThisFv
== None:
598 for FvName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
599 Buffer
= StringIO
.StringIO('')
600 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[FvName
]
601 FvObj
.AddToBuffer(Buffer
)
604 if GenFds
.OnlyGenerateThisFv
== None and GenFds
.OnlyGenerateThisFd
== None and GenFds
.OnlyGenerateThisCap
== None:
605 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
606 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
607 for CapsuleName
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
608 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[CapsuleName
]
609 CapsuleObj
.GenCapsule()
611 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
612 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
613 for DriverName
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.keys():
614 OptRomObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
[DriverName
]
615 OptRomObj
.AddToBuffer(None)
617 def GenFfsMakefile(OutputDir
, FdfParser
, WorkSpace
, ArchList
, GlobalData
):
618 GenFdsGlobalVariable
.SetEnv(FdfParser
, WorkSpace
, ArchList
, GlobalData
)
619 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
620 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
621 FdObj
.GenFd(Flag
=True)
623 for FvName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
624 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[FvName
]
625 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
627 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
628 for DriverName
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.keys():
629 OptRomObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
[DriverName
]
630 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
632 return GenFdsGlobalVariable
.FfsCmdDict
636 # @param FvObj Whose block size to get
637 # @retval int Block size value
639 def GetFvBlockSize(FvObj
):
640 DefaultBlockSize
= 0x1
642 if GenFds
.OnlyGenerateThisFd
!= None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
643 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
645 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
646 for ElementRegion
in ElementFd
.RegionList
:
647 if ElementRegion
.RegionType
== 'FV':
648 for ElementRegionData
in ElementRegion
.RegionDataList
:
649 if ElementRegionData
!= None and ElementRegionData
.upper() == FvObj
.UiFvName
:
650 if FvObj
.BlockSizeList
!= []:
651 return FvObj
.BlockSizeList
[0][0]
653 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
654 if FvObj
.BlockSizeList
!= []:
655 return FvObj
.BlockSizeList
[0][0]
656 return DefaultBlockSize
658 for ElementRegion
in FdObj
.RegionList
:
659 if ElementRegion
.RegionType
== 'FV':
660 for ElementRegionData
in ElementRegion
.RegionDataList
:
661 if ElementRegionData
!= None and ElementRegionData
.upper() == FvObj
.UiFvName
:
662 if FvObj
.BlockSizeList
!= []:
663 return FvObj
.BlockSizeList
[0][0]
665 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
666 return DefaultBlockSize
668 ## DisplayFvSpaceInfo()
670 # @param FvObj Whose block size to get
673 def DisplayFvSpaceInfo(FdfParser
):
677 for FvName
in FdfParser
.Profile
.FvDict
:
678 if len(FvName
) > MaxFvNameLength
:
679 MaxFvNameLength
= len(FvName
)
680 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
681 if os
.path
.exists(FvSpaceInfoFileName
):
682 FileLinesList
= linecache
.getlines(FvSpaceInfoFileName
)
689 for Line
in FileLinesList
:
690 NameValue
= Line
.split('=')
691 if len(NameValue
) == 2:
692 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
694 Total
= NameValue
[1].strip()
695 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
697 Used
= NameValue
[1].strip()
698 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
700 Free
= NameValue
[1].strip()
702 if TotalFound
and UsedFound
and FreeFound
:
703 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
705 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
706 for FvSpaceInfo
in FvSpaceInfoList
:
707 Name
= FvSpaceInfo
[0]
708 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
709 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
710 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
711 if UsedSizeValue
== TotalSizeValue
:
714 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
716 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
720 # @param BuildDb Database from build meta data files
721 # @param DscFile modules from dsc file will be preprocessed
724 def PreprocessImage(BuildDb
, DscFile
):
725 PcdDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
728 PcdObj
= PcdDict
[Key
]
729 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
730 PcdValue
= PcdObj
.DefaultValue
736 Int64PcdValue
= long(PcdValue
, 0)
737 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
741 if Int64PcdValue
> 0:
742 TopAddress
= Int64PcdValue
744 ModuleDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
745 for Key
in ModuleDict
:
746 ModuleObj
= BuildDb
.BuildObject
[Key
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
747 print ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
749 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
750 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
751 GuidXRefFile
= StringIO
.StringIO('')
755 for Arch
in ArchList
:
756 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
757 for ModuleFile
in PlatformDataBase
.Modules
:
758 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
759 if Module
in ModuleList
:
762 ModuleList
.append(Module
)
763 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
764 for key
, item
in Module
.Protocols
.items():
766 for key
, item
in Module
.Guids
.items():
768 for key
, item
in Module
.Ppis
.items():
770 for FvName
in FdfParserObj
.Profile
.FvDict
:
771 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
772 if not isinstance(FfsObj
, FfsFileStatement
.FileStatement
):
773 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
774 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
775 if FdfModule
in ModuleList
:
778 ModuleList
.append(FdfModule
)
779 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
780 for key
, item
in FdfModule
.Protocols
.items():
782 for key
, item
in FdfModule
.Guids
.items():
784 for key
, item
in FdfModule
.Ppis
.items():
787 FileStatementGuid
= FfsObj
.NameGuid
788 if FileStatementGuid
in FileGuidList
:
791 FileGuidList
.append(FileStatementGuid
)
793 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
794 FfsPath
= glob
.glob(os
.path
.join(FfsPath
, FileStatementGuid
) + '*')
797 if not os
.path
.exists(FfsPath
[0]):
800 ReFileEnds
= re
.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
801 FileList
= os
.listdir(FfsPath
[0])
802 for File
in FileList
:
803 Match
= ReFileEnds
.search(File
)
805 for Index
in range(1, 8):
806 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
807 MatchDict
[Match
.group(Index
)].append(File
)
808 elif Match
.group(Index
):
809 MatchDict
[Match
.group(Index
)] = [File
]
812 if '.ui' in MatchDict
:
813 for File
in MatchDict
['.ui']:
814 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
818 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
819 Name
= ''.join([chr(c
) for c
in TmpStr
[:-1]])
822 if 'fv.sec.txt' in MatchDict
:
823 FileList
= MatchDict
['fv.sec.txt']
824 elif '.pe32.txt' in MatchDict
:
825 FileList
= MatchDict
['.pe32.txt']
826 elif '.te.txt' in MatchDict
:
827 FileList
= MatchDict
['.te.txt']
828 elif '.pic.txt' in MatchDict
:
829 FileList
= MatchDict
['.pic.txt']
830 elif '.raw.txt' in MatchDict
:
831 FileList
= MatchDict
['.raw.txt']
832 elif '.ffs.txt' in MatchDict
:
833 FileList
= MatchDict
['.ffs.txt']
836 for File
in FileList
:
837 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
838 Name
.append((F
.read().split()[-1]))
842 Name
= ' '.join(Name
) if type(Name
) == type([]) else Name
843 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
845 # Append GUIDs, Protocols, and PPIs to the Xref file
846 GuidXRefFile
.write("\n")
847 for key
, item
in GuidDict
.items():
848 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
850 if GuidXRefFile
.getvalue():
851 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
852 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
853 elif os
.path
.exists(GuidXRefFileName
):
854 os
.remove(GuidXRefFileName
)
857 ##Define GenFd as static function
858 GenFd
= staticmethod(GenFd
)
859 GetFvBlockSize
= staticmethod(GetFvBlockSize
)
860 DisplayFvSpaceInfo
= staticmethod(DisplayFvSpaceInfo
)
861 PreprocessImage
= staticmethod(PreprocessImage
)
862 GenerateGuidXRefFile
= staticmethod(GenerateGuidXRefFile
)
864 if __name__
== '__main__':
866 ## 0-127 is a safe return range, and 1 is a standard default error
867 if r
< 0 or r
> 127: r
= 1