2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 import Common
.LongFilePathOs
as os
27 from struct
import pack
28 from UserDict
import IterableUserDict
29 from UserList
import UserList
31 from Common
import EdkLogger
as EdkLogger
32 from Common
import GlobalData
as GlobalData
33 from DataType
import *
34 from BuildToolError
import *
35 from CommonDataClass
.DataClass
import *
36 from Parsing
import GetSplitValueList
37 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
38 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
40 ## Regular expression used to find out place holders in string template
41 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE | re
.UNICODE
)
43 ## Dictionary used to store file time stamp for quick re-access
44 gFileTimeStampCache
= {} # {file path : file time stamp}
46 ## Dictionary used to store dependencies of files
47 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
49 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
50 """ Parse map file to get variable offset in current EFI file
51 @param mapfilepath Map file absolution path
52 @param efifilepath: EFI binary file full path
53 @param varnames iteratable container whose elements are variable names to be searched
55 @return List whos elements are tuple with variable name and raw offset
59 f
= open(mapfilepath
, 'r')
65 if len(lines
) == 0: return None
66 firstline
= lines
[0].strip()
67 if (firstline
.startswith("Archive member included ") and
68 firstline
.endswith(" file (symbol)")):
69 return _parseForGCC(lines
, efifilepath
, varnames
)
70 if firstline
.startswith("# Path:"):
71 return _parseForXcode(lines
, efifilepath
, varnames
)
72 return _parseGeneral(lines
, efifilepath
, varnames
)
74 def _parseForXcode(lines
, efifilepath
, varnames
):
77 for index
, line
in enumerate(lines
):
79 if status
== 0 and line
== "# Symbols:":
82 if status
== 1 and len(line
) != 0:
83 for varname
in varnames
:
85 m
= re
.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname
, line
)
87 ret
.append((varname
, m
.group(1)))
90 def _parseForGCC(lines
, efifilepath
, varnames
):
91 """ Parse map file generated by GCC linker """
95 for index
, line
in enumerate(lines
):
97 # status machine transection
98 if status
== 0 and line
== "Memory Configuration":
101 elif status
== 1 and line
== 'Linker script and memory map':
104 elif status
==2 and line
== 'START GROUP':
110 m
= re
.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line
)
112 sections
.append(m
.groups(0))
113 for varname
in varnames
:
115 m
= re
.match("^.data.(%s)" % varname
, line
)
117 m
= re
.match(".data.(%s)$" % varname
, line
)
119 Str
= lines
[index
+ 1]
121 Str
= line
[len(".data.%s" % varname
):]
123 m
= re
.match('^([\da-fA-Fx]+) +([\da-fA-Fx]+)', Str
.strip())
125 varoffset
.append((varname
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
129 # get section information from efi file
130 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
131 if efisecs
== None or len(efisecs
) == 0:
135 for efisec
in efisecs
:
136 for section
in sections
:
137 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
138 redirection
= int(section
[1], 16) - efisec
[1]
141 for var
in varoffset
:
142 for efisec
in efisecs
:
143 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
144 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
147 def _parseGeneral(lines
, efifilepath
, varnames
):
148 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
149 secs
= [] # key = section name
151 secRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
152 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
156 if re
.match("^Start[' ']+Length[' ']+Name[' ']+Class", line
):
159 if re
.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line
):
162 if re
.match("^entry point at", line
):
165 if status
== 1 and len(line
) != 0:
166 m
= secRe
.match(line
)
167 assert m
!= None, "Fail to parse the section in map file , line is %s" % line
168 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
169 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
170 if status
== 2 and len(line
) != 0:
171 for varname
in varnames
:
172 m
= symRe
.match(line
)
173 assert m
!= None, "Fail to parse the symbol in map file, line is %s" % line
174 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
175 sec_no
= int(sec_no
, 16)
176 sym_offset
= int(sym_offset
, 16)
177 vir_addr
= int(vir_addr
, 16)
178 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
180 # fond a binary pcd entry in map file
182 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
183 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
185 if not varoffset
: return []
187 # get section information from efi file
188 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
189 if efisecs
== None or len(efisecs
) == 0:
193 for var
in varoffset
:
195 for efisec
in efisecs
:
197 if var
[1].strip() == efisec
[0].strip():
198 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
199 elif var
[4] == index
:
200 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
204 ## Routine to process duplicated INF
206 # This function is called by following two cases:
209 # Pkg/module/module.inf
210 # Pkg/module/module.inf {
212 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
215 # INF Pkg/module/module.inf
216 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
218 # This function copies Pkg/module/module.inf to
219 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
221 # @param Path Original PathClass object
222 # @param BaseName New file base name
224 # @retval return the new PathClass object
226 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
227 Filename
= os
.path
.split(Path
.File
)[1]
229 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
231 Filename
= BaseName
+ Path
.BaseName
234 # If -N is specified on command line, cache is disabled
235 # The directory has to be created
237 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
238 if not os
.path
.exists(DbDir
):
241 # A temporary INF is copied to database path which must have write permission
242 # The temporary will be removed at the end of build
243 # In case of name conflict, the file name is
244 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
246 TempFullPath
= os
.path
.join(DbDir
,
248 RtPath
= PathClass(Path
.File
, Workspace
)
250 # Modify the full path to temporary path, keep other unchanged
252 # To build same module more than once, the module path with FILE_GUID overridden has
253 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
254 # in DSC which is used as relative path by C files and other files in INF.
255 # A trick was used: all module paths are PathClass instances, after the initialization
256 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
258 # The reason for creating a temporary INF is:
259 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
260 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
261 # A different key for the same module is needed to create different output directory,
262 # retrieve overridden PCDs, library instances.
264 # The BaseName is the FILE_GUID which is also the output directory name.
267 RtPath
.Path
= TempFullPath
268 RtPath
.BaseName
= BaseName
270 # If file exists, compare contents
272 if os
.path
.exists(TempFullPath
):
273 with
open(str(Path
), 'rb') as f1
: Src
= f1
.read()
274 with
open(TempFullPath
, 'rb') as f2
: Dst
= f2
.read()
277 GlobalData
.gTempInfs
.append(TempFullPath
)
278 shutil
.copy2(str(Path
), TempFullPath
)
281 ## Remove temporary created INFs whose paths were saved in gTempInfs
283 def ClearDuplicatedInf():
284 for File
in GlobalData
.gTempInfs
:
285 if os
.path
.exists(File
):
288 ## callback routine for processing variable option
290 # This function can be used to process variable number of option values. The
291 # typical usage of it is specify architecure list on command line.
292 # (e.g. <tool> -a IA32 X64 IPF)
294 # @param Option Standard callback function parameter
295 # @param OptionString Standard callback function parameter
296 # @param Value Standard callback function parameter
297 # @param Parser Standard callback function parameter
301 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
304 RawArgs
= Parser
.rargs
307 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
308 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
312 setattr(Parser
.values
, Option
.dest
, Value
)
314 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
316 # @param Guid The GUID string
318 # @retval string The GUID string in C structure style
320 def GuidStringToGuidStructureString(Guid
):
321 GuidList
= Guid
.split('-')
323 for Index
in range(0, 3, 1):
324 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
325 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
326 for Index
in range(0, 12, 2):
327 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
331 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
333 # @param GuidValue The GUID value in byte array
335 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
337 def GuidStructureByteArrayToGuidString(GuidValue
):
338 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
339 guidValueList
= guidValueString
.split(",")
340 if len(guidValueList
) != 16:
342 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
344 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
345 int(guidValueList
[3], 16),
346 int(guidValueList
[2], 16),
347 int(guidValueList
[1], 16),
348 int(guidValueList
[0], 16),
349 int(guidValueList
[5], 16),
350 int(guidValueList
[4], 16),
351 int(guidValueList
[7], 16),
352 int(guidValueList
[6], 16),
353 int(guidValueList
[8], 16),
354 int(guidValueList
[9], 16),
355 int(guidValueList
[10], 16),
356 int(guidValueList
[11], 16),
357 int(guidValueList
[12], 16),
358 int(guidValueList
[13], 16),
359 int(guidValueList
[14], 16),
360 int(guidValueList
[15], 16)
365 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
367 # @param GuidValue The GUID value in C structure format
369 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
371 def GuidStructureStringToGuidString(GuidValue
):
372 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
373 guidValueList
= guidValueString
.split(",")
374 if len(guidValueList
) != 11:
376 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
378 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
379 int(guidValueList
[0], 16),
380 int(guidValueList
[1], 16),
381 int(guidValueList
[2], 16),
382 int(guidValueList
[3], 16),
383 int(guidValueList
[4], 16),
384 int(guidValueList
[5], 16),
385 int(guidValueList
[6], 16),
386 int(guidValueList
[7], 16),
387 int(guidValueList
[8], 16),
388 int(guidValueList
[9], 16),
389 int(guidValueList
[10], 16)
394 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
396 # @param GuidValue The GUID value in C structure format
398 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
400 def GuidStructureStringToGuidValueName(GuidValue
):
401 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
402 guidValueList
= guidValueString
.split(",")
403 if len(guidValueList
) != 11:
404 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
405 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
406 int(guidValueList
[0], 16),
407 int(guidValueList
[1], 16),
408 int(guidValueList
[2], 16),
409 int(guidValueList
[3], 16),
410 int(guidValueList
[4], 16),
411 int(guidValueList
[5], 16),
412 int(guidValueList
[6], 16),
413 int(guidValueList
[7], 16),
414 int(guidValueList
[8], 16),
415 int(guidValueList
[9], 16),
416 int(guidValueList
[10], 16)
419 ## Create directories
421 # @param Directory The directory name
423 def CreateDirectory(Directory
):
424 if Directory
== None or Directory
.strip() == "":
427 if not os
.access(Directory
, os
.F_OK
):
428 os
.makedirs(Directory
)
433 ## Remove directories, including files and sub-directories in it
435 # @param Directory The directory name
437 def RemoveDirectory(Directory
, Recursively
=False):
438 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
441 CurrentDirectory
= os
.getcwd()
443 for File
in os
.listdir("."):
444 if os
.path
.isdir(File
):
445 RemoveDirectory(File
, Recursively
)
448 os
.chdir(CurrentDirectory
)
451 ## Check if given file is changed or not
453 # This method is used to check if a file is changed or not between two build
454 # actions. It makes use a cache to store files timestamp.
456 # @param File The path of file
458 # @retval True If the given file is changed, doesn't exist, or can't be
459 # found in timestamp cache
460 # @retval False If the given file is changed
463 if not os
.path
.exists(File
):
466 FileState
= os
.stat(File
)
467 TimeStamp
= FileState
[-2]
469 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
473 gFileTimeStampCache
[File
] = TimeStamp
477 ## Store content in file
479 # This method is used to save file only when its content is changed. This is
480 # quite useful for "make" system to decide what will be re-built and what won't.
482 # @param File The path of file
483 # @param Content The new content of the file
484 # @param IsBinaryFile The flag indicating if the file is binary file or not
486 # @retval True If the file content is changed and the file is renewed
487 # @retval False If the file content is the same
489 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
491 Content
= Content
.replace("\n", os
.linesep
)
493 if os
.path
.exists(File
):
495 if Content
== open(File
, "rb").read():
498 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
500 DirName
= os
.path
.dirname(File
)
501 if not CreateDirectory(DirName
):
502 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
505 DirName
= os
.getcwd()
506 if not os
.access(DirName
, os
.W_OK
):
507 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
510 if GlobalData
.gIsWindows
:
512 from PyUtility
import SaveFileToDisk
513 if not SaveFileToDisk(File
, Content
):
514 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
516 Fd
= open(File
, "wb")
520 Fd
= open(File
, "wb")
524 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
528 ## Make a Python object persistent on file system
530 # @param Data The object to be stored in file
531 # @param File The path of file to store the object
533 def DataDump(Data
, File
):
536 Fd
= open(File
, 'wb')
537 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
539 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
544 ## Restore a Python object from a file
546 # @param File The path of file stored the object
548 # @retval object A python object
549 # @retval None If failure in file operation
551 def DataRestore(File
):
555 Fd
= open(File
, 'rb')
556 Data
= cPickle
.load(Fd
)
558 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
565 ## Retrieve and cache the real path name in file system
567 # @param Root The root directory of path relative to
569 # @retval str The path string if the path exists
570 # @retval None If path doesn't exist
576 def __init__(self
, Root
):
578 for F
in os
.listdir(Root
):
580 self
._UPPER
_CACHE
_[F
.upper()] = F
583 def __getitem__(self
, Path
):
584 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
587 if Path
and Path
[0] == os
.path
.sep
:
589 if Path
in self
._CACHE
_:
590 return os
.path
.join(self
._Root
, Path
)
591 UpperPath
= Path
.upper()
592 if UpperPath
in self
._UPPER
_CACHE
_:
593 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
597 SepIndex
= Path
.find(os
.path
.sep
)
599 Parent
= UpperPath
[:SepIndex
]
600 if Parent
not in self
._UPPER
_CACHE
_:
602 LastSepIndex
= SepIndex
603 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
605 if LastSepIndex
== -1:
610 SepIndex
= LastSepIndex
612 Parent
= Path
[:SepIndex
]
613 ParentKey
= UpperPath
[:SepIndex
]
614 if ParentKey
not in self
._UPPER
_CACHE
_:
618 if Parent
in self
._CACHE
_:
621 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
622 for F
in os
.listdir(ParentDir
):
623 Dir
= os
.path
.join(ParentDir
, F
)
624 self
._CACHE
_.add(Dir
)
625 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
627 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
630 if Path
in self
._CACHE
_:
631 return os
.path
.join(self
._Root
, Path
)
632 elif UpperPath
in self
._UPPER
_CACHE
_:
633 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
636 ## Get all files of a directory
638 # @param Root: Root dir
639 # @param SkipList : The files need be skipped
641 # @retval A list of all files
643 def GetFiles(Root
, SkipList
=None, FullPath
=True):
646 for Root
, Dirs
, Files
in os
.walk(Root
):
648 for Item
in SkipList
:
653 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
655 File
= File
[len(OriPath
) + 1:]
656 FileList
.append(File
)
660 ## Check if gvien file exists or not
662 # @param File File name or path to be checked
663 # @param Dir The directory the file is relative to
665 # @retval True if file exists
666 # @retval False if file doesn't exists
668 def ValidFile(File
, Ext
=None):
670 Dummy
, FileExt
= os
.path
.splitext(File
)
671 if FileExt
.lower() != Ext
.lower():
673 if not os
.path
.exists(File
):
677 def RealPath(File
, Dir
='', OverrideDir
=''):
678 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
679 NewFile
= GlobalData
.gAllFiles
[NewFile
]
680 if not NewFile
and OverrideDir
:
681 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
682 NewFile
= GlobalData
.gAllFiles
[NewFile
]
685 def RealPath2(File
, Dir
='', OverrideDir
=''):
688 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
690 if OverrideDir
[-1] == os
.path
.sep
:
691 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
693 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
694 if GlobalData
.gAllFiles
:
695 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
697 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
698 if not os
.path
.exists(NewFile
):
702 if Dir
[-1] == os
.path
.sep
:
703 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
705 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
711 ## Check if gvien file exists or not
714 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
717 Dummy
, FileExt
= os
.path
.splitext(File
)
718 if FileExt
.lower() != Ext
.lower():
721 # Replace the Edk macros
722 if OverrideDir
!= '' and OverrideDir
!= None:
723 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
724 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
725 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
726 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
728 # Replace the default dir to current dir
731 Dir
= Dir
[len(Workspace
) + 1:]
733 # First check if File has Edk definition itself
734 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
735 NewFile
= File
.replace('$(EFI_SOURCE)', EfiSource
)
736 NewFile
= NewFile
.replace('$(EDK_SOURCE)', EdkSource
)
737 NewFile
= AllFiles
[os
.path
.normpath(NewFile
)]
741 # Second check the path with override value
742 if OverrideDir
!= '' and OverrideDir
!= None:
743 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
747 # Last check the path with normal definitions
748 File
= os
.path
.join(Dir
, File
)
749 NewFile
= AllFiles
[os
.path
.normpath(File
)]
755 ## Check if gvien file exists or not
758 def ValidFile3(AllFiles
, File
, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
759 # Replace the Edk macros
760 if OverrideDir
!= '' and OverrideDir
!= None:
761 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
762 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
763 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
764 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
766 # Replace the default dir to current dir
767 # Dir is current module dir related to workspace
770 Dir
= Dir
[len(Workspace
) + 1:]
773 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
774 NewRelaPath
= RelaPath
777 # First check if File has Edk definition itself
778 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
779 File
= File
.replace('$(EFI_SOURCE)', EfiSource
)
780 File
= File
.replace('$(EDK_SOURCE)', EdkSource
)
781 NewFile
= AllFiles
[os
.path
.normpath(File
)]
783 NewRelaPath
= os
.path
.dirname(NewFile
)
784 File
= os
.path
.basename(NewFile
)
785 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
788 # Second check the path with override value
789 if OverrideDir
!= '' and OverrideDir
!= None:
790 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
792 #NewRelaPath = os.path.dirname(NewFile)
793 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
796 # Last check the path with normal definitions
797 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
804 return NewRelaPath
, RelaPath
, File
807 def GetRelPath(Path1
, Path2
):
808 FileName
= os
.path
.basename(Path2
)
809 L1
= os
.path
.normpath(Path1
).split(os
.path
.normpath('/'))
810 L2
= os
.path
.normpath(Path2
).split(os
.path
.normpath('/'))
811 for Index
in range(0, len(L1
)):
812 if L1
[Index
] != L2
[Index
]:
813 FileName
= '../' * (len(L1
) - Index
)
814 for Index2
in range(Index
, len(L2
)):
815 FileName
= os
.path
.join(FileName
, L2
[Index2
])
817 return os
.path
.normpath(FileName
)
820 ## Get GUID value from given packages
822 # @param CName The CName of the GUID
823 # @param PackageList List of packages looking-up in
824 # @param Inffile The driver file
826 # @retval GuidValue if the CName is found in any given package
827 # @retval None if the CName is not found in all given packages
829 def GuidValue(CName
, PackageList
, Inffile
= None):
830 for P
in PackageList
:
831 GuidKeys
= P
.Guids
.keys()
832 if Inffile
and P
._PrivateGuids
:
833 if not Inffile
.startswith(P
.MetaFile
.Dir
):
834 GuidKeys
= (dict.fromkeys(x
for x
in P
.Guids
if x
not in P
._PrivateGuids
)).keys()
835 if CName
in GuidKeys
:
836 return P
.Guids
[CName
]
839 ## Get Protocol value from given packages
841 # @param CName The CName of the GUID
842 # @param PackageList List of packages looking-up in
843 # @param Inffile The driver file
845 # @retval GuidValue if the CName is found in any given package
846 # @retval None if the CName is not found in all given packages
848 def ProtocolValue(CName
, PackageList
, Inffile
= None):
849 for P
in PackageList
:
850 ProtocolKeys
= P
.Protocols
.keys()
851 if Inffile
and P
._PrivateProtocols
:
852 if not Inffile
.startswith(P
.MetaFile
.Dir
):
853 ProtocolKeys
= (dict.fromkeys(x
for x
in P
.Protocols
if x
not in P
._PrivateProtocols
)).keys()
854 if CName
in ProtocolKeys
:
855 return P
.Protocols
[CName
]
858 ## Get PPI value from given packages
860 # @param CName The CName of the GUID
861 # @param PackageList List of packages looking-up in
862 # @param Inffile The driver file
864 # @retval GuidValue if the CName is found in any given package
865 # @retval None if the CName is not found in all given packages
867 def PpiValue(CName
, PackageList
, Inffile
= None):
868 for P
in PackageList
:
869 PpiKeys
= P
.Ppis
.keys()
870 if Inffile
and P
._PrivatePpis
:
871 if not Inffile
.startswith(P
.MetaFile
.Dir
):
872 PpiKeys
= (dict.fromkeys(x
for x
in P
.Ppis
if x
not in P
._PrivatePpis
)).keys()
877 ## A string template class
879 # This class implements a template for string replacement. A string template
880 # looks like following
882 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
884 # The string between ${BEGIN} and ${END} will be repeated as many times as the
885 # length of "placeholder_name", which is a list passed through a dict. The
886 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
887 # be not used and, in this case, the "placeholder_name" must not a list and it
888 # will just be replaced once.
890 class TemplateString(object):
891 _REPEAT_START_FLAG
= "BEGIN"
892 _REPEAT_END_FLAG
= "END"
894 class Section(object):
895 _LIST_TYPES
= [type([]), type(set()), type((0,))]
897 def __init__(self
, TemplateSection
, PlaceHolderList
):
898 self
._Template
= TemplateSection
899 self
._PlaceHolderList
= []
901 # Split the section into sub-sections according to the position of placeholders
903 self
._SubSectionList
= []
906 # The placeholders passed in must be in the format of
908 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
910 for PlaceHolder
, Start
, End
in PlaceHolderList
:
911 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
912 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
913 self
._PlaceHolderList
.append(PlaceHolder
)
914 SubSectionStart
= End
915 if SubSectionStart
< len(TemplateSection
):
916 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
918 self
._SubSectionList
= [TemplateSection
]
921 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
923 def Instantiate(self
, PlaceHolderValues
):
925 RepeatPlaceHolders
= {}
926 NonRepeatPlaceHolders
= {}
928 for PlaceHolder
in self
._PlaceHolderList
:
929 if PlaceHolder
not in PlaceHolderValues
:
931 Value
= PlaceHolderValues
[PlaceHolder
]
932 if type(Value
) in self
._LIST
_TYPES
:
934 RepeatTime
= len(Value
)
935 elif RepeatTime
!= len(Value
):
939 "${%s} has different repeat time from others!" % PlaceHolder
,
940 ExtraData
=str(self
._Template
)
942 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
944 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
946 if NonRepeatPlaceHolders
:
948 for S
in self
._SubSectionList
:
949 if S
not in NonRepeatPlaceHolders
:
952 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
954 StringList
= self
._SubSectionList
956 if RepeatPlaceHolders
:
958 for Index
in range(RepeatTime
):
960 if S
not in RepeatPlaceHolders
:
961 TempStringList
.append(S
)
963 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
964 StringList
= TempStringList
966 return "".join(StringList
)
969 def __init__(self
, Template
=None):
971 self
.IsBinary
= False
972 self
._Template
= Template
973 self
._TemplateSectionList
= self
._Parse
(Template
)
977 # @retval string The string replaced
982 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
984 # @retval list A list of TemplateString.Section objects
986 def _Parse(self
, Template
):
991 TemplateSectionList
= []
993 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
995 if MatchEnd
<= len(Template
):
996 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
997 TemplateSectionList
.append(TemplateSection
)
1000 MatchString
= MatchObj
.group(1)
1001 MatchStart
= MatchObj
.start()
1002 MatchEnd
= MatchObj
.end()
1004 if MatchString
== self
._REPEAT
_START
_FLAG
:
1005 if MatchStart
> SectionStart
:
1006 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
1007 TemplateSectionList
.append(TemplateSection
)
1008 SectionStart
= MatchEnd
1009 PlaceHolderList
= []
1010 elif MatchString
== self
._REPEAT
_END
_FLAG
:
1011 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
1012 TemplateSectionList
.append(TemplateSection
)
1013 SectionStart
= MatchEnd
1014 PlaceHolderList
= []
1016 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
1017 SearchFrom
= MatchEnd
1018 return TemplateSectionList
1020 ## Replace the string template with dictionary of placeholders and append it to previous one
1022 # @param AppendString The string template to append
1023 # @param Dictionary The placeholder dictionaries
1025 def Append(self
, AppendString
, Dictionary
=None):
1027 SectionList
= self
._Parse
(AppendString
)
1028 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
1030 self
.String
+= AppendString
1032 ## Replace the string template with dictionary of placeholders
1034 # @param Dictionary The placeholder dictionaries
1036 # @retval str The string replaced with placeholder values
1038 def Replace(self
, Dictionary
=None):
1039 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
1041 ## Progress indicator class
1043 # This class makes use of thread to print progress on console.
1046 # for avoiding deadloop
1048 _ProgressThread
= None
1049 _CheckInterval
= 0.25
1053 # @param OpenMessage The string printed before progress charaters
1054 # @param CloseMessage The string printed after progress charaters
1055 # @param ProgressChar The charater used to indicate the progress
1056 # @param Interval The interval in seconds between two progress charaters
1058 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
1059 self
.PromptMessage
= OpenMessage
1060 self
.CodaMessage
= CloseMessage
1061 self
.ProgressChar
= ProgressChar
1062 self
.Interval
= Interval
1063 if Progressor
._StopFlag
== None:
1064 Progressor
._StopFlag
= threading
.Event()
1066 ## Start to print progress charater
1068 # @param OpenMessage The string printed before progress charaters
1070 def Start(self
, OpenMessage
=None):
1071 if OpenMessage
!= None:
1072 self
.PromptMessage
= OpenMessage
1073 Progressor
._StopFlag
.clear()
1074 if Progressor
._ProgressThread
== None:
1075 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
1076 Progressor
._ProgressThread
.setDaemon(False)
1077 Progressor
._ProgressThread
.start()
1079 ## Stop printing progress charater
1081 # @param CloseMessage The string printed after progress charaters
1083 def Stop(self
, CloseMessage
=None):
1084 OriginalCodaMessage
= self
.CodaMessage
1085 if CloseMessage
!= None:
1086 self
.CodaMessage
= CloseMessage
1088 self
.CodaMessage
= OriginalCodaMessage
1090 ## Thread entry method
1091 def _ProgressThreadEntry(self
):
1092 sys
.stdout
.write(self
.PromptMessage
+ " ")
1095 while not Progressor
._StopFlag
.isSet():
1097 sys
.stdout
.write(self
.ProgressChar
)
1099 TimeUp
= self
.Interval
1100 time
.sleep(self
._CheckInterval
)
1101 TimeUp
-= self
._CheckInterval
1102 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
1105 ## Abort the progress display
1108 if Progressor
._StopFlag
!= None:
1109 Progressor
._StopFlag
.set()
1110 if Progressor
._ProgressThread
!= None:
1111 Progressor
._ProgressThread
.join()
1112 Progressor
._ProgressThread
= None
1114 ## A dict which can access its keys and/or values orderly
1116 # The class implements a new kind of dict which its keys or values can be
1117 # accessed in the order they are added into the dict. It guarantees the order
1118 # by making use of an internal list to keep a copy of keys.
1120 class sdict(IterableUserDict
):
1123 IterableUserDict
.__init
__(self
)
1127 def __setitem__(self
, key
, value
):
1128 if key
not in self
._key
_list
:
1129 self
._key
_list
.append(key
)
1130 IterableUserDict
.__setitem
__(self
, key
, value
)
1133 def __delitem__(self
, key
):
1134 self
._key
_list
.remove(key
)
1135 IterableUserDict
.__delitem
__(self
, key
)
1137 ## used in "for k in dict" loop to ensure the correct order
1139 return self
.iterkeys()
1143 return len(self
._key
_list
)
1145 ## "in" test support
1146 def __contains__(self
, key
):
1147 return key
in self
._key
_list
1150 def index(self
, key
):
1151 return self
._key
_list
.index(key
)
1154 def insert(self
, key
, newkey
, newvalue
, order
):
1155 index
= self
._key
_list
.index(key
)
1156 if order
== 'BEFORE':
1157 self
._key
_list
.insert(index
, newkey
)
1158 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1159 elif order
== 'AFTER':
1160 self
._key
_list
.insert(index
+ 1, newkey
)
1161 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1164 def append(self
, sdict
):
1166 if key
not in self
._key
_list
:
1167 self
._key
_list
.append(key
)
1168 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
1170 def has_key(self
, key
):
1171 return key
in self
._key
_list
1176 IterableUserDict
.clear(self
)
1178 ## Return a copy of keys
1181 for key
in self
._key
_list
:
1185 ## Return a copy of values
1188 for key
in self
._key
_list
:
1189 values
.append(self
[key
])
1192 ## Return a copy of (key, value) list
1195 for key
in self
._key
_list
:
1196 items
.append((key
, self
[key
]))
1199 ## Iteration support
1200 def iteritems(self
):
1201 return iter(self
.items())
1203 ## Keys interation support
1205 return iter(self
.keys())
1207 ## Values interation support
1208 def itervalues(self
):
1209 return iter(self
.values())
1211 ## Return value related to a key, and remove the (key, value) from the dict
1212 def pop(self
, key
, *dv
):
1214 if key
in self
._key
_list
:
1216 self
.__delitem
__(key
)
1221 ## Return (key, value) pair, and remove the (key, value) from the dict
1223 key
= self
._key
_list
[-1]
1225 self
.__delitem
__(key
)
1228 def update(self
, dict=None, **kwargs
):
1230 for k
, v
in dict.items():
1233 for k
, v
in kwargs
.items():
1236 ## Dictionary with restricted keys
1240 def __init__(self
, KeyList
):
1242 dict.__setitem
__(self
, Key
, "")
1245 def __setitem__(self
, key
, value
):
1247 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1248 ExtraData
=", ".join(dict.keys(self
)))
1249 dict.__setitem
__(self
, key
, value
)
1252 def __getitem__(self
, key
):
1255 return dict.__getitem
__(self
, key
)
1258 def __delitem__(self
, key
):
1259 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1264 self
.__setitem
__(Key
, "")
1266 ## Return value related to a key, and remove the (key, value) from the dict
1267 def pop(self
, key
, *dv
):
1268 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1270 ## Return (key, value) pair, and remove the (key, value) from the dict
1272 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1274 ## Dictionary using prioritized list as key
1277 _ListType
= type([])
1278 _TupleType
= type(())
1279 _Wildcard
= 'COMMON'
1280 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1282 def __init__(self
, _Single_
=False, _Level_
=2):
1283 self
._Level
_ = _Level_
1285 self
._Single
_ = _Single_
1288 def __getitem__(self
, key
):
1291 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1295 elif self
._Level
_ > 1:
1296 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1299 if self
._Level
_ > 1:
1300 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1302 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1303 FirstKey
= self
._Wildcard
1306 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1308 return self
._GetAllValues
(FirstKey
, RestKeys
)
1310 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1312 #print "%s-%s" % (FirstKey, self._Level_) ,
1313 if self
._Level
_ > 1:
1314 if FirstKey
== self
._Wildcard
:
1315 if FirstKey
in self
.data
:
1316 Value
= self
.data
[FirstKey
][RestKeys
]
1318 for Key
in self
.data
:
1319 Value
= self
.data
[Key
][RestKeys
]
1320 if Value
!= None: break
1322 if FirstKey
in self
.data
:
1323 Value
= self
.data
[FirstKey
][RestKeys
]
1324 if Value
== None and self
._Wildcard
in self
.data
:
1326 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1328 if FirstKey
== self
._Wildcard
:
1329 if FirstKey
in self
.data
:
1330 Value
= self
.data
[FirstKey
]
1332 for Key
in self
.data
:
1333 Value
= self
.data
[Key
]
1334 if Value
!= None: break
1336 if FirstKey
in self
.data
:
1337 Value
= self
.data
[FirstKey
]
1338 elif self
._Wildcard
in self
.data
:
1339 Value
= self
.data
[self
._Wildcard
]
1342 def _GetAllValues(self
, FirstKey
, RestKeys
):
1344 if self
._Level
_ > 1:
1345 if FirstKey
== self
._Wildcard
:
1346 for Key
in self
.data
:
1347 Value
+= self
.data
[Key
][RestKeys
]
1349 if FirstKey
in self
.data
:
1350 Value
+= self
.data
[FirstKey
][RestKeys
]
1351 if self
._Wildcard
in self
.data
:
1352 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1354 if FirstKey
== self
._Wildcard
:
1355 for Key
in self
.data
:
1356 Value
.append(self
.data
[Key
])
1358 if FirstKey
in self
.data
:
1359 Value
.append(self
.data
[FirstKey
])
1360 if self
._Wildcard
in self
.data
:
1361 Value
.append(self
.data
[self
._Wildcard
])
1365 def __setitem__(self
, key
, value
):
1368 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1373 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1376 if self
._Level
_ > 1:
1377 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1379 if FirstKey
in self
._ValidWildcardList
:
1380 FirstKey
= self
._Wildcard
1382 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1383 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1385 if self
._Level
_ > 1:
1386 self
.data
[FirstKey
][RestKeys
] = value
1388 self
.data
[FirstKey
] = value
1390 def SetGreedyMode(self
):
1391 self
._Single
_ = False
1392 if self
._Level
_ > 1:
1393 for Key
in self
.data
:
1394 self
.data
[Key
].SetGreedyMode()
1396 def SetSingleMode(self
):
1397 self
._Single
_ = True
1398 if self
._Level
_ > 1:
1399 for Key
in self
.data
:
1400 self
.data
[Key
].SetSingleMode()
1402 def GetKeys(self
, KeyIndex
=0):
1403 assert KeyIndex
>= 0
1405 return set(self
.data
.keys())
1408 for Key
in self
.data
:
1409 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1412 ## Boolean chain list
1414 class Blist(UserList
):
1415 def __init__(self
, initlist
=None):
1416 UserList
.__init
__(self
, initlist
)
1417 def __setitem__(self
, i
, item
):
1418 if item
not in [True, False]:
1424 def _GetResult(self
):
1426 for item
in self
.data
:
1429 Result
= property(_GetResult
)
1431 def ParseConsoleLog(Filename
):
1432 Opr
= open(os
.path
.normpath(Filename
), 'r')
1433 Opw
= open(os
.path
.normpath(Filename
+ '.New'), 'w+')
1434 for Line
in Opr
.readlines():
1435 if Line
.find('.efi') > -1:
1436 Line
= Line
[Line
.rfind(' ') : Line
.rfind('.efi')].strip()
1437 Opw
.write('%s\n' % Line
)
1442 def AnalyzePcdExpression(Setting
):
1443 Setting
= Setting
.strip()
1444 # There might be escaped quote in a string: \", \\\"
1445 Data
= Setting
.replace('\\\\', '//').replace('\\\"', '\\\'')
1446 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1453 elif ch
== '(' and not InStr
:
1455 elif ch
== ')' and not InStr
:
1458 if (Pair
> 0 or InStr
) and ch
== TAB_VALUE_SPLIT
:
1465 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1467 FieldList
.append(Setting
[StartPos
:].strip())
1469 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1476 # Analyze DSC PCD value, since there is no data type info in DSC
1477 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1478 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1479 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1480 # 3. Dynamic default:
1481 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1482 # TokenSpace.PcdCName|PcdValue
1484 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1485 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1487 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1488 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1489 # there might have "|" operator, also in string value.
1491 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1492 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1493 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1495 # ValueList: A List contain fields described above
1496 # IsValid: True if conforming EBNF, otherwise False
1497 # Index: The index where PcdValue is in ValueList
1499 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1500 FieldList
= AnalyzePcdExpression(Setting
)
1503 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1504 Value
= FieldList
[0]
1506 if len(FieldList
) > 1:
1508 # Fix the PCD type when no DataType input
1513 if len(FieldList
) > 2:
1515 if DataType
== 'VOID*':
1516 IsValid
= (len(FieldList
) <= 3)
1518 IsValid
= (len(FieldList
) <= 1)
1519 return [Value
, '', Size
], IsValid
, 0
1520 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1521 Value
= FieldList
[0]
1523 if len(FieldList
) > 1:
1527 if len(FieldList
) > 2:
1531 if Value
.startswith("L"):
1532 Size
= str((len(Value
)- 3 + 1) * 2)
1533 elif Value
.startswith("{"):
1534 Size
= str(len(Value
.split(",")))
1536 Size
= str(len(Value
) -2 + 1 )
1537 if DataType
== 'VOID*':
1538 IsValid
= (len(FieldList
) <= 3)
1540 IsValid
= (len(FieldList
) <= 1)
1541 return [Value
, Type
, Size
], IsValid
, 0
1542 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1543 VpdOffset
= FieldList
[0]
1545 if not DataType
== 'VOID*':
1546 if len(FieldList
) > 1:
1547 Value
= FieldList
[1]
1549 if len(FieldList
) > 1:
1551 if len(FieldList
) > 2:
1552 Value
= FieldList
[2]
1553 if DataType
== 'VOID*':
1554 IsValid
= (len(FieldList
) <= 3)
1556 IsValid
= (len(FieldList
) <= 2)
1557 return [VpdOffset
, Size
, Value
], IsValid
, 2
1558 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1559 HiiString
= FieldList
[0]
1560 Guid
= Offset
= Value
= Attribute
= ''
1561 if len(FieldList
) > 1:
1563 if len(FieldList
) > 2:
1564 Offset
= FieldList
[2]
1565 if len(FieldList
) > 3:
1566 Value
= FieldList
[3]
1567 if len(FieldList
) > 4:
1568 Attribute
= FieldList
[4]
1569 IsValid
= (3 <= len(FieldList
) <= 5)
1570 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1575 # Analyze the pcd Value, Datum type and TokenNumber.
1576 # Used to avoid split issue while the value string contain "|" character
1578 # @param[in] Setting: A String contain value/datum type/token number information;
1580 # @retval ValueList: A List contain value, datum type and toke number.
1582 def AnalyzePcdData(Setting
):
1583 ValueList
= ['', '', '']
1585 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1586 PtrValue
= ValueRe
.findall(Setting
)
1588 ValueUpdateFlag
= False
1590 if len(PtrValue
) >= 1:
1591 Setting
= re
.sub(ValueRe
, '', Setting
)
1592 ValueUpdateFlag
= True
1594 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1595 ValueList
[0:len(TokenList
)] = TokenList
1598 ValueList
[0] = PtrValue
[0]
1602 ## AnalyzeHiiPcdData
1604 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1605 # Used to avoid split issue while the value string contain "|" character
1607 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1609 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1611 def AnalyzeHiiPcdData(Setting
):
1612 ValueList
= ['', '', '', '']
1614 TokenList
= GetSplitValueList(Setting
)
1615 ValueList
[0:len(TokenList
)] = TokenList
1619 ## AnalyzeVpdPcdData
1621 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1622 # Used to avoid split issue while the value string contain "|" character
1624 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1626 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1628 def AnalyzeVpdPcdData(Setting
):
1629 ValueList
= ['', '', '']
1631 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1632 PtrValue
= ValueRe
.findall(Setting
)
1634 ValueUpdateFlag
= False
1636 if len(PtrValue
) >= 1:
1637 Setting
= re
.sub(ValueRe
, '', Setting
)
1638 ValueUpdateFlag
= True
1640 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1641 ValueList
[0:len(TokenList
)] = TokenList
1644 ValueList
[2] = PtrValue
[0]
1648 ## check format of PCD value against its the datum type
1650 # For PCD value setting
1652 def CheckPcdDatum(Type
, Value
):
1654 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1655 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1656 or (Value
.startswith('{') and Value
.endswith('}'))
1658 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1659 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1660 elif ValueRe
.match(Value
):
1661 # Check the chars in UnicodeString or CString is printable
1662 if Value
.startswith("L"):
1666 Printset
= set(string
.printable
)
1667 Printset
.remove(TAB_PRINTCHAR_VT
)
1668 Printset
.add(TAB_PRINTCHAR_BS
)
1669 Printset
.add(TAB_PRINTCHAR_NUL
)
1670 if not set(Value
).issubset(Printset
):
1671 PrintList
= list(Printset
)
1673 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1674 elif Type
== 'BOOLEAN':
1675 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1676 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1677 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1678 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1680 Value
= long(Value
, 0)
1682 return False, "Invalid value [%s] of type [%s];"\
1683 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1685 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type
)
1689 ## Split command line option string to list
1691 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1692 # in non-windows platform to launch command
1694 def SplitOption(OptionString
):
1699 for Index
in range(0, len(OptionString
)):
1700 CurrentChar
= OptionString
[Index
]
1701 if CurrentChar
in ['"', "'"]:
1702 if QuotationMark
== CurrentChar
:
1704 elif QuotationMark
== "":
1705 QuotationMark
= CurrentChar
1710 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1711 if Index
> OptionStart
:
1712 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1714 LastChar
= CurrentChar
1715 OptionList
.append(OptionString
[OptionStart
:])
1718 def CommonPath(PathList
):
1719 P1
= min(PathList
).split(os
.path
.sep
)
1720 P2
= max(PathList
).split(os
.path
.sep
)
1721 for Index
in xrange(min(len(P1
), len(P2
))):
1722 if P1
[Index
] != P2
[Index
]:
1723 return os
.path
.sep
.join(P1
[:Index
])
1724 return os
.path
.sep
.join(P1
)
1727 # Convert string to C format array
1729 def ConvertStringToByteArray(Value
):
1730 Value
= Value
.strip()
1734 if not Value
.endswith('}'):
1736 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1737 ValFields
= Value
.split(',')
1739 for Index
in range(len(ValFields
)):
1740 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1743 Value
= '{' + ','.join(ValFields
) + '}'
1747 if Value
.startswith('L"'):
1748 if not Value
.endswith('"'):
1752 elif not Value
.startswith('"') or not Value
.endswith('"'):
1755 Value
= eval(Value
) # translate escape character
1757 for Index
in range(0,len(Value
)):
1759 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1761 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1762 Value
= NewValue
+ '0}'
1765 class PathClass(object):
1766 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1767 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1769 self
.File
= str(File
)
1770 if os
.path
.isabs(self
.File
):
1774 self
.Root
= str(Root
)
1775 self
.AlterRoot
= str(AlterRoot
)
1777 # Remove any '.' and '..' in path
1779 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1780 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1781 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1782 # eliminate the side-effect of 'C:'
1783 if self
.Root
[-1] == ':':
1784 self
.Root
+= os
.path
.sep
1785 # file path should not start with path separator
1786 if self
.Root
[-1] == os
.path
.sep
:
1787 self
.File
= self
.Path
[len(self
.Root
):]
1789 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1791 self
.Path
= os
.path
.normpath(self
.File
)
1793 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1794 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1798 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1800 self
.Dir
= self
.Root
1802 self
.Dir
= self
.SubDir
1807 self
.Type
= self
.Ext
.lower()
1809 self
.IsBinary
= IsBinary
1810 self
.Target
= Target
1811 self
.TagName
= TagName
1812 self
.ToolCode
= ToolCode
1813 self
.ToolChainFamily
= ToolChainFamily
1817 ## Convert the object of this class to a string
1819 # Convert member Path of the class to a string
1821 # @retval string Formatted String
1826 ## Override __eq__ function
1828 # Check whether PathClass are the same
1830 # @retval False The two PathClass are different
1831 # @retval True The two PathClass are the same
1833 def __eq__(self
, Other
):
1834 if type(Other
) == type(self
):
1835 return self
.Path
== Other
.Path
1837 return self
.Path
== str(Other
)
1839 ## Override __cmp__ function
1841 # Customize the comparsion operation of two PathClass
1843 # @retval 0 The two PathClass are different
1844 # @retval -1 The first PathClass is less than the second PathClass
1845 # @retval 1 The first PathClass is Bigger than the second PathClass
1846 def __cmp__(self
, Other
):
1847 if type(Other
) == type(self
):
1848 OtherKey
= Other
.Path
1850 OtherKey
= str(Other
)
1853 if SelfKey
== OtherKey
:
1855 elif SelfKey
> OtherKey
:
1860 ## Override __hash__ function
1862 # Use Path as key in hash table
1864 # @retval string Key for hash table
1867 return hash(self
.Path
)
1869 def _GetFileKey(self
):
1870 if self
._Key
== None:
1871 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1874 def _GetTimeStamp(self
):
1875 return os
.stat(self
.Path
)[8]
1877 def Validate(self
, Type
='', CaseSensitive
=True):
1878 if GlobalData
.gCaseInsensitive
:
1879 CaseSensitive
= False
1880 if Type
and Type
.lower() != self
.Type
:
1881 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1883 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1884 if not RealRoot
and not RealFile
:
1885 RealFile
= self
.File
1887 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1889 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1890 if len (mws
.getPkgPath()) == 0:
1891 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1893 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1897 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1898 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1899 ErrorCode
= FILE_CASE_MISMATCH
1900 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1902 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1903 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1905 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1908 self
.File
= RealFile
1909 self
.Root
= RealRoot
1910 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1911 return ErrorCode
, ErrorInfo
1913 Key
= property(_GetFileKey
)
1914 TimeStamp
= property(_GetTimeStamp
)
1916 ## Parse PE image to get the required PE informaion.
1918 class PeImageClass():
1921 # @param File FilePath of PeImage
1923 def __init__(self
, PeFile
):
1924 self
.FileName
= PeFile
1925 self
.IsValid
= False
1928 self
.SectionAlignment
= 0
1929 self
.SectionHeaderList
= []
1932 PeObject
= open(PeFile
, 'rb')
1934 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1937 ByteArray
= array
.array('B')
1938 ByteArray
.fromfile(PeObject
, 0x3E)
1939 ByteList
= ByteArray
.tolist()
1940 # DOS signature should be 'MZ'
1941 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1942 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1945 # Read 4 byte PE Signature
1946 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1947 PeObject
.seek(PeOffset
)
1948 ByteArray
= array
.array('B')
1949 ByteArray
.fromfile(PeObject
, 4)
1950 # PE signature should be 'PE\0\0'
1951 if ByteArray
.tostring() != 'PE\0\0':
1952 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1955 # Read PE file header
1956 ByteArray
= array
.array('B')
1957 ByteArray
.fromfile(PeObject
, 0x14)
1958 ByteList
= ByteArray
.tolist()
1959 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1961 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1964 # Read PE optional header
1965 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1966 ByteArray
= array
.array('B')
1967 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1968 ByteList
= ByteArray
.tolist()
1969 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1970 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1971 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1973 # Read each Section Header
1974 for Index
in range(SecNumber
):
1975 ByteArray
= array
.array('B')
1976 ByteArray
.fromfile(PeObject
, 0x28)
1977 ByteList
= ByteArray
.tolist()
1978 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1979 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1980 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1981 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1982 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1986 def _ByteListToStr(self
, ByteList
):
1988 for index
in range(len(ByteList
)):
1989 if ByteList
[index
] == 0:
1991 String
+= chr(ByteList
[index
])
1994 def _ByteListToInt(self
, ByteList
):
1996 for index
in range(len(ByteList
) - 1, -1, -1):
1997 Value
= (Value
<< 8) |
int(ByteList
[index
])
2007 def __init__(self
,SkuIdentifier
='', SkuIds
={}):
2009 self
.AvailableSkuIds
= sdict()
2011 self
.SkuIdNumberSet
= []
2012 if SkuIdentifier
== '' or SkuIdentifier
is None:
2013 self
.SkuIdSet
= ['DEFAULT']
2014 self
.SkuIdNumberSet
= ['0U']
2015 elif SkuIdentifier
== 'ALL':
2016 self
.SkuIdSet
= SkuIds
.keys()
2017 self
.SkuIdNumberSet
= [num
.strip() + 'U' for num
in SkuIds
.values()]
2019 r
= SkuIdentifier
.split('|')
2020 self
.SkuIdSet
=[r
[k
].strip() for k
in range(len(r
))]
2023 self
.SkuIdNumberSet
= [SkuIds
[k
].strip() + 'U' for k
in self
.SkuIdSet
]
2025 EdkLogger
.error("build", PARAMETER_INVALID
,
2026 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
2027 % (k
, " | ".join(SkuIds
.keys())))
2028 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
and SkuIdentifier
!= 'ALL':
2029 self
.SkuIdSet
.remove('DEFAULT')
2030 self
.SkuIdNumberSet
.remove('0U')
2031 for each
in self
.SkuIdSet
:
2033 self
.AvailableSkuIds
[each
] = SkuIds
[each
]
2035 EdkLogger
.error("build", PARAMETER_INVALID
,
2036 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
2037 % (each
, " | ".join(SkuIds
.keys())))
2039 def __SkuUsageType(self
):
2041 if len(self
.SkuIdSet
) == 1:
2042 if self
.SkuIdSet
[0] == 'DEFAULT':
2043 return SkuClass
.DEFAULT
2045 return SkuClass
.SINGLE
2047 return SkuClass
.MULTIPLE
2049 def __GetAvailableSkuIds(self
):
2050 return self
.AvailableSkuIds
2052 def __GetSystemSkuID(self
):
2053 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2054 return self
.SkuIdSet
[0]
2057 def __GetAvailableSkuIdNumber(self
):
2058 return self
.SkuIdNumberSet
2059 SystemSkuId
= property(__GetSystemSkuID
)
2060 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2061 SkuUsageType
= property(__SkuUsageType
)
2062 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2065 # Pack a registry format GUID
2067 def PackRegistryFormatGuid(Guid
):
2068 Guid
= Guid
.split('-')
2069 return pack('=LHHBBBBBBBB',
2073 int(Guid
[3][-4:-2], 16),
2074 int(Guid
[3][-2:], 16),
2075 int(Guid
[4][-12:-10], 16),
2076 int(Guid
[4][-10:-8], 16),
2077 int(Guid
[4][-8:-6], 16),
2078 int(Guid
[4][-6:-4], 16),
2079 int(Guid
[4][-4:-2], 16),
2080 int(Guid
[4][-2:], 16)
2083 def BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, Value
):
2084 if PcdDatumType
== 'VOID*':
2085 if Value
.startswith('L'):
2087 EdkLogger
.error("build", FORMAT_INVALID
, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"')
2088 Value
= Value
[0] + '"' + Value
[1:] + '"'
2089 elif Value
.startswith('H'):
2091 EdkLogger
.error("build", FORMAT_INVALID
, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"')
2095 EdkLogger
.error("build", FORMAT_INVALID
, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"')
2096 Value
= '"' + Value
+ '"'
2098 IsValid
, Cause
= CheckPcdDatum(PcdDatumType
, Value
)
2100 EdkLogger
.error("build", FORMAT_INVALID
, Cause
, ExtraData
="%s.%s" % (TokenSpaceGuidCName
, TokenCName
))
2101 if PcdDatumType
== 'BOOLEAN':
2102 Value
= Value
.upper()
2103 if Value
== 'TRUE' or Value
== '1':
2105 elif Value
== 'FALSE' or Value
== '0':
2111 # This acts like the main() function for the script, unless it is 'import'ed into another
2114 if __name__
== '__main__':