2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2016, 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 return _parseGeneral(lines
, efifilepath
, varnames
)
72 def _parseForGCC(lines
, efifilepath
, varnames
):
73 """ Parse map file generated by GCC linker """
79 # status machine transection
80 if status
== 0 and line
== "Memory Configuration":
83 elif status
== 1 and line
== 'Linker script and memory map':
86 elif status
==2 and line
== 'START GROUP':
92 m
= re
.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line
)
94 sections
.append(m
.groups(0))
95 for varname
in varnames
:
96 m
= re
.match("^([\da-fA-Fx]+) +[_]*(%s)$" % varname
, line
)
98 varoffset
.append((varname
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
102 # get section information from efi file
103 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
104 if efisecs
== None or len(efisecs
) == 0:
108 for efisec
in efisecs
:
109 for section
in sections
:
110 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
111 redirection
= int(section
[1], 16) - efisec
[1]
114 for var
in varoffset
:
115 for efisec
in efisecs
:
116 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
117 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
120 def _parseGeneral(lines
, efifilepath
, varnames
):
121 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
122 secs
= [] # key = section name
124 secRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
125 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
129 if re
.match("^Start[' ']+Length[' ']+Name[' ']+Class", line
):
132 if re
.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line
):
135 if re
.match("^entry point at", line
):
138 if status
== 1 and len(line
) != 0:
139 m
= secRe
.match(line
)
140 assert m
!= None, "Fail to parse the section in map file , line is %s" % line
141 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
142 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
143 if status
== 2 and len(line
) != 0:
144 for varname
in varnames
:
145 m
= symRe
.match(line
)
146 assert m
!= None, "Fail to parse the symbol in map file, line is %s" % line
147 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
148 sec_no
= int(sec_no
, 16)
149 sym_offset
= int(sym_offset
, 16)
150 vir_addr
= int(vir_addr
, 16)
151 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
153 # fond a binary pcd entry in map file
155 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
156 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
158 if not varoffset
: return []
160 # get section information from efi file
161 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
162 if efisecs
== None or len(efisecs
) == 0:
166 for var
in varoffset
:
168 for efisec
in efisecs
:
170 if var
[1].strip() == efisec
[0].strip():
171 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
172 elif var
[4] == index
:
173 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
177 ## Routine to process duplicated INF
179 # This function is called by following two cases:
182 # Pkg/module/module.inf
183 # Pkg/module/module.inf {
185 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
188 # INF Pkg/module/module.inf
189 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
191 # This function copies Pkg/module/module.inf to
192 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
194 # @param Path Original PathClass object
195 # @param BaseName New file base name
197 # @retval return the new PathClass object
199 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
200 Filename
= os
.path
.split(Path
.File
)[1]
202 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
204 Filename
= BaseName
+ Path
.BaseName
207 # If -N is specified on command line, cache is disabled
208 # The directory has to be created
210 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
211 if not os
.path
.exists(DbDir
):
214 # A temporary INF is copied to database path which must have write permission
215 # The temporary will be removed at the end of build
216 # In case of name conflict, the file name is
217 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
219 TempFullPath
= os
.path
.join(DbDir
,
221 RtPath
= PathClass(Path
.File
, Workspace
)
223 # Modify the full path to temporary path, keep other unchanged
225 # To build same module more than once, the module path with FILE_GUID overridden has
226 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
227 # in DSC which is used as relative path by C files and other files in INF.
228 # A trick was used: all module paths are PathClass instances, after the initialization
229 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
231 # The reason for creating a temporary INF is:
232 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
233 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
234 # A different key for the same module is needed to create different output directory,
235 # retrieve overridden PCDs, library instances.
237 # The BaseName is the FILE_GUID which is also the output directory name.
240 RtPath
.Path
= TempFullPath
241 RtPath
.BaseName
= BaseName
243 # If file exists, compare contents
245 if os
.path
.exists(TempFullPath
):
246 with
open(str(Path
), 'rb') as f1
: Src
= f1
.read()
247 with
open(TempFullPath
, 'rb') as f2
: Dst
= f2
.read()
250 GlobalData
.gTempInfs
.append(TempFullPath
)
251 shutil
.copy2(str(Path
), TempFullPath
)
254 ## Remove temporary created INFs whose paths were saved in gTempInfs
256 def ClearDuplicatedInf():
257 for File
in GlobalData
.gTempInfs
:
258 if os
.path
.exists(File
):
261 ## callback routine for processing variable option
263 # This function can be used to process variable number of option values. The
264 # typical usage of it is specify architecure list on command line.
265 # (e.g. <tool> -a IA32 X64 IPF)
267 # @param Option Standard callback function parameter
268 # @param OptionString Standard callback function parameter
269 # @param Value Standard callback function parameter
270 # @param Parser Standard callback function parameter
274 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
277 RawArgs
= Parser
.rargs
280 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
281 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
285 setattr(Parser
.values
, Option
.dest
, Value
)
287 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
289 # @param Guid The GUID string
291 # @retval string The GUID string in C structure style
293 def GuidStringToGuidStructureString(Guid
):
294 GuidList
= Guid
.split('-')
296 for Index
in range(0, 3, 1):
297 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
298 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
299 for Index
in range(0, 12, 2):
300 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
304 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
306 # @param GuidValue The GUID value in byte array
308 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
310 def GuidStructureByteArrayToGuidString(GuidValue
):
311 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
312 guidValueList
= guidValueString
.split(",")
313 if len(guidValueList
) != 16:
315 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
317 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
318 int(guidValueList
[3], 16),
319 int(guidValueList
[2], 16),
320 int(guidValueList
[1], 16),
321 int(guidValueList
[0], 16),
322 int(guidValueList
[5], 16),
323 int(guidValueList
[4], 16),
324 int(guidValueList
[7], 16),
325 int(guidValueList
[6], 16),
326 int(guidValueList
[8], 16),
327 int(guidValueList
[9], 16),
328 int(guidValueList
[10], 16),
329 int(guidValueList
[11], 16),
330 int(guidValueList
[12], 16),
331 int(guidValueList
[13], 16),
332 int(guidValueList
[14], 16),
333 int(guidValueList
[15], 16)
338 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
340 # @param GuidValue The GUID value in C structure format
342 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
344 def GuidStructureStringToGuidString(GuidValue
):
345 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
346 guidValueList
= guidValueString
.split(",")
347 if len(guidValueList
) != 11:
349 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
351 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
352 int(guidValueList
[0], 16),
353 int(guidValueList
[1], 16),
354 int(guidValueList
[2], 16),
355 int(guidValueList
[3], 16),
356 int(guidValueList
[4], 16),
357 int(guidValueList
[5], 16),
358 int(guidValueList
[6], 16),
359 int(guidValueList
[7], 16),
360 int(guidValueList
[8], 16),
361 int(guidValueList
[9], 16),
362 int(guidValueList
[10], 16)
367 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
369 # @param GuidValue The GUID value in C structure format
371 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
373 def GuidStructureStringToGuidValueName(GuidValue
):
374 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
375 guidValueList
= guidValueString
.split(",")
376 if len(guidValueList
) != 11:
377 EdkLogger
.error(None, FORMAT_INVALID
, "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)
392 ## Create directories
394 # @param Directory The directory name
396 def CreateDirectory(Directory
):
397 if Directory
== None or Directory
.strip() == "":
400 if not os
.access(Directory
, os
.F_OK
):
401 os
.makedirs(Directory
)
406 ## Remove directories, including files and sub-directories in it
408 # @param Directory The directory name
410 def RemoveDirectory(Directory
, Recursively
=False):
411 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
414 CurrentDirectory
= os
.getcwd()
416 for File
in os
.listdir("."):
417 if os
.path
.isdir(File
):
418 RemoveDirectory(File
, Recursively
)
421 os
.chdir(CurrentDirectory
)
424 ## Check if given file is changed or not
426 # This method is used to check if a file is changed or not between two build
427 # actions. It makes use a cache to store files timestamp.
429 # @param File The path of file
431 # @retval True If the given file is changed, doesn't exist, or can't be
432 # found in timestamp cache
433 # @retval False If the given file is changed
436 if not os
.path
.exists(File
):
439 FileState
= os
.stat(File
)
440 TimeStamp
= FileState
[-2]
442 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
446 gFileTimeStampCache
[File
] = TimeStamp
450 ## Store content in file
452 # This method is used to save file only when its content is changed. This is
453 # quite useful for "make" system to decide what will be re-built and what won't.
455 # @param File The path of file
456 # @param Content The new content of the file
457 # @param IsBinaryFile The flag indicating if the file is binary file or not
459 # @retval True If the file content is changed and the file is renewed
460 # @retval False If the file content is the same
462 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
464 Content
= Content
.replace("\n", os
.linesep
)
466 if os
.path
.exists(File
):
468 if Content
== open(File
, "rb").read():
471 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
473 DirName
= os
.path
.dirname(File
)
474 if not CreateDirectory(DirName
):
475 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
478 DirName
= os
.getcwd()
479 if not os
.access(DirName
, os
.W_OK
):
480 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
483 if GlobalData
.gIsWindows
:
485 from PyUtility
import SaveFileToDisk
486 if not SaveFileToDisk(File
, Content
):
487 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
489 Fd
= open(File
, "wb")
493 Fd
= open(File
, "wb")
497 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
501 ## Make a Python object persistent on file system
503 # @param Data The object to be stored in file
504 # @param File The path of file to store the object
506 def DataDump(Data
, File
):
509 Fd
= open(File
, 'wb')
510 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
512 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
517 ## Restore a Python object from a file
519 # @param File The path of file stored the object
521 # @retval object A python object
522 # @retval None If failure in file operation
524 def DataRestore(File
):
528 Fd
= open(File
, 'rb')
529 Data
= cPickle
.load(Fd
)
531 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
538 ## Retrieve and cache the real path name in file system
540 # @param Root The root directory of path relative to
542 # @retval str The path string if the path exists
543 # @retval None If path doesn't exist
549 def __init__(self
, Root
):
551 for F
in os
.listdir(Root
):
553 self
._UPPER
_CACHE
_[F
.upper()] = F
556 def __getitem__(self
, Path
):
557 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
560 if Path
and Path
[0] == os
.path
.sep
:
562 if Path
in self
._CACHE
_:
563 return os
.path
.join(self
._Root
, Path
)
564 UpperPath
= Path
.upper()
565 if UpperPath
in self
._UPPER
_CACHE
_:
566 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
570 SepIndex
= Path
.find(os
.path
.sep
)
572 Parent
= UpperPath
[:SepIndex
]
573 if Parent
not in self
._UPPER
_CACHE
_:
575 LastSepIndex
= SepIndex
576 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
578 if LastSepIndex
== -1:
583 SepIndex
= LastSepIndex
585 Parent
= Path
[:SepIndex
]
586 ParentKey
= UpperPath
[:SepIndex
]
587 if ParentKey
not in self
._UPPER
_CACHE
_:
591 if Parent
in self
._CACHE
_:
594 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
595 for F
in os
.listdir(ParentDir
):
596 Dir
= os
.path
.join(ParentDir
, F
)
597 self
._CACHE
_.add(Dir
)
598 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
600 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
603 if Path
in self
._CACHE
_:
604 return os
.path
.join(self
._Root
, Path
)
605 elif UpperPath
in self
._UPPER
_CACHE
_:
606 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
609 ## Get all files of a directory
611 # @param Root: Root dir
612 # @param SkipList : The files need be skipped
614 # @retval A list of all files
616 def GetFiles(Root
, SkipList
=None, FullPath
=True):
619 for Root
, Dirs
, Files
in os
.walk(Root
):
621 for Item
in SkipList
:
626 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
628 File
= File
[len(OriPath
) + 1:]
629 FileList
.append(File
)
633 ## Check if gvien file exists or not
635 # @param File File name or path to be checked
636 # @param Dir The directory the file is relative to
638 # @retval True if file exists
639 # @retval False if file doesn't exists
641 def ValidFile(File
, Ext
=None):
643 Dummy
, FileExt
= os
.path
.splitext(File
)
644 if FileExt
.lower() != Ext
.lower():
646 if not os
.path
.exists(File
):
650 def RealPath(File
, Dir
='', OverrideDir
=''):
651 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
652 NewFile
= GlobalData
.gAllFiles
[NewFile
]
653 if not NewFile
and OverrideDir
:
654 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
655 NewFile
= GlobalData
.gAllFiles
[NewFile
]
658 def RealPath2(File
, Dir
='', OverrideDir
=''):
661 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
663 if OverrideDir
[-1] == os
.path
.sep
:
664 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
666 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
667 if GlobalData
.gAllFiles
:
668 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
670 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
671 if not os
.path
.exists(NewFile
):
675 if Dir
[-1] == os
.path
.sep
:
676 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
678 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
684 ## Check if gvien file exists or not
687 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
690 Dummy
, FileExt
= os
.path
.splitext(File
)
691 if FileExt
.lower() != Ext
.lower():
694 # Replace the Edk macros
695 if OverrideDir
!= '' and OverrideDir
!= None:
696 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
697 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
698 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
699 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
701 # Replace the default dir to current dir
704 Dir
= Dir
[len(Workspace
) + 1:]
706 # First check if File has Edk definition itself
707 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
708 NewFile
= File
.replace('$(EFI_SOURCE)', EfiSource
)
709 NewFile
= NewFile
.replace('$(EDK_SOURCE)', EdkSource
)
710 NewFile
= AllFiles
[os
.path
.normpath(NewFile
)]
714 # Second check the path with override value
715 if OverrideDir
!= '' and OverrideDir
!= None:
716 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
720 # Last check the path with normal definitions
721 File
= os
.path
.join(Dir
, File
)
722 NewFile
= AllFiles
[os
.path
.normpath(File
)]
728 ## Check if gvien file exists or not
731 def ValidFile3(AllFiles
, File
, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
732 # Replace the Edk macros
733 if OverrideDir
!= '' and OverrideDir
!= None:
734 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
735 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
736 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
737 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
739 # Replace the default dir to current dir
740 # Dir is current module dir related to workspace
743 Dir
= Dir
[len(Workspace
) + 1:]
746 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
747 NewRelaPath
= RelaPath
750 # First check if File has Edk definition itself
751 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
752 File
= File
.replace('$(EFI_SOURCE)', EfiSource
)
753 File
= File
.replace('$(EDK_SOURCE)', EdkSource
)
754 NewFile
= AllFiles
[os
.path
.normpath(File
)]
756 NewRelaPath
= os
.path
.dirname(NewFile
)
757 File
= os
.path
.basename(NewFile
)
758 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
761 # Second check the path with override value
762 if OverrideDir
!= '' and OverrideDir
!= None:
763 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
765 #NewRelaPath = os.path.dirname(NewFile)
766 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
769 # Last check the path with normal definitions
770 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
777 return NewRelaPath
, RelaPath
, File
780 def GetRelPath(Path1
, Path2
):
781 FileName
= os
.path
.basename(Path2
)
782 L1
= os
.path
.normpath(Path1
).split(os
.path
.normpath('/'))
783 L2
= os
.path
.normpath(Path2
).split(os
.path
.normpath('/'))
784 for Index
in range(0, len(L1
)):
785 if L1
[Index
] != L2
[Index
]:
786 FileName
= '../' * (len(L1
) - Index
)
787 for Index2
in range(Index
, len(L2
)):
788 FileName
= os
.path
.join(FileName
, L2
[Index2
])
790 return os
.path
.normpath(FileName
)
793 ## Get GUID value from given packages
795 # @param CName The CName of the GUID
796 # @param PackageList List of packages looking-up in
797 # @param Inffile The driver file
799 # @retval GuidValue if the CName is found in any given package
800 # @retval None if the CName is not found in all given packages
802 def GuidValue(CName
, PackageList
, Inffile
= None):
803 for P
in PackageList
:
804 GuidKeys
= P
.Guids
.keys()
805 if Inffile
and P
._PrivateGuids
:
806 if not Inffile
.startswith(P
.MetaFile
.Dir
):
807 GuidKeys
= (dict.fromkeys(x
for x
in P
.Guids
if x
not in P
._PrivateGuids
)).keys()
808 if CName
in GuidKeys
:
809 return P
.Guids
[CName
]
812 ## Get Protocol value from given packages
814 # @param CName The CName of the GUID
815 # @param PackageList List of packages looking-up in
816 # @param Inffile The driver file
818 # @retval GuidValue if the CName is found in any given package
819 # @retval None if the CName is not found in all given packages
821 def ProtocolValue(CName
, PackageList
, Inffile
= None):
822 for P
in PackageList
:
823 ProtocolKeys
= P
.Protocols
.keys()
824 if Inffile
and P
._PrivateProtocols
:
825 if not Inffile
.startswith(P
.MetaFile
.Dir
):
826 ProtocolKeys
= (dict.fromkeys(x
for x
in P
.Protocols
if x
not in P
._PrivateProtocols
)).keys()
827 if CName
in ProtocolKeys
:
828 return P
.Protocols
[CName
]
831 ## Get PPI value from given packages
833 # @param CName The CName of the GUID
834 # @param PackageList List of packages looking-up in
835 # @param Inffile The driver file
837 # @retval GuidValue if the CName is found in any given package
838 # @retval None if the CName is not found in all given packages
840 def PpiValue(CName
, PackageList
, Inffile
= None):
841 for P
in PackageList
:
842 PpiKeys
= P
.Ppis
.keys()
843 if Inffile
and P
._PrivatePpis
:
844 if not Inffile
.startswith(P
.MetaFile
.Dir
):
845 PpiKeys
= (dict.fromkeys(x
for x
in P
.Ppis
if x
not in P
._PrivatePpis
)).keys()
850 ## A string template class
852 # This class implements a template for string replacement. A string template
853 # looks like following
855 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
857 # The string between ${BEGIN} and ${END} will be repeated as many times as the
858 # length of "placeholder_name", which is a list passed through a dict. The
859 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
860 # be not used and, in this case, the "placeholder_name" must not a list and it
861 # will just be replaced once.
863 class TemplateString(object):
864 _REPEAT_START_FLAG
= "BEGIN"
865 _REPEAT_END_FLAG
= "END"
867 class Section(object):
868 _LIST_TYPES
= [type([]), type(set()), type((0,))]
870 def __init__(self
, TemplateSection
, PlaceHolderList
):
871 self
._Template
= TemplateSection
872 self
._PlaceHolderList
= []
874 # Split the section into sub-sections according to the position of placeholders
876 self
._SubSectionList
= []
879 # The placeholders passed in must be in the format of
881 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
883 for PlaceHolder
, Start
, End
in PlaceHolderList
:
884 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
885 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
886 self
._PlaceHolderList
.append(PlaceHolder
)
887 SubSectionStart
= End
888 if SubSectionStart
< len(TemplateSection
):
889 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
891 self
._SubSectionList
= [TemplateSection
]
894 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
896 def Instantiate(self
, PlaceHolderValues
):
898 RepeatPlaceHolders
= {}
899 NonRepeatPlaceHolders
= {}
901 for PlaceHolder
in self
._PlaceHolderList
:
902 if PlaceHolder
not in PlaceHolderValues
:
904 Value
= PlaceHolderValues
[PlaceHolder
]
905 if type(Value
) in self
._LIST
_TYPES
:
907 RepeatTime
= len(Value
)
908 elif RepeatTime
!= len(Value
):
912 "${%s} has different repeat time from others!" % PlaceHolder
,
913 ExtraData
=str(self
._Template
)
915 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
917 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
919 if NonRepeatPlaceHolders
:
921 for S
in self
._SubSectionList
:
922 if S
not in NonRepeatPlaceHolders
:
925 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
927 StringList
= self
._SubSectionList
929 if RepeatPlaceHolders
:
931 for Index
in range(RepeatTime
):
933 if S
not in RepeatPlaceHolders
:
934 TempStringList
.append(S
)
936 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
937 StringList
= TempStringList
939 return "".join(StringList
)
942 def __init__(self
, Template
=None):
944 self
.IsBinary
= False
945 self
._Template
= Template
946 self
._TemplateSectionList
= self
._Parse
(Template
)
950 # @retval string The string replaced
955 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
957 # @retval list A list of TemplateString.Section objects
959 def _Parse(self
, Template
):
964 TemplateSectionList
= []
966 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
968 if MatchEnd
<= len(Template
):
969 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
970 TemplateSectionList
.append(TemplateSection
)
973 MatchString
= MatchObj
.group(1)
974 MatchStart
= MatchObj
.start()
975 MatchEnd
= MatchObj
.end()
977 if MatchString
== self
._REPEAT
_START
_FLAG
:
978 if MatchStart
> SectionStart
:
979 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
980 TemplateSectionList
.append(TemplateSection
)
981 SectionStart
= MatchEnd
983 elif MatchString
== self
._REPEAT
_END
_FLAG
:
984 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
985 TemplateSectionList
.append(TemplateSection
)
986 SectionStart
= MatchEnd
989 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
990 SearchFrom
= MatchEnd
991 return TemplateSectionList
993 ## Replace the string template with dictionary of placeholders and append it to previous one
995 # @param AppendString The string template to append
996 # @param Dictionary The placeholder dictionaries
998 def Append(self
, AppendString
, Dictionary
=None):
1000 SectionList
= self
._Parse
(AppendString
)
1001 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
1003 self
.String
+= AppendString
1005 ## Replace the string template with dictionary of placeholders
1007 # @param Dictionary The placeholder dictionaries
1009 # @retval str The string replaced with placeholder values
1011 def Replace(self
, Dictionary
=None):
1012 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
1014 ## Progress indicator class
1016 # This class makes use of thread to print progress on console.
1019 # for avoiding deadloop
1021 _ProgressThread
= None
1022 _CheckInterval
= 0.25
1026 # @param OpenMessage The string printed before progress charaters
1027 # @param CloseMessage The string printed after progress charaters
1028 # @param ProgressChar The charater used to indicate the progress
1029 # @param Interval The interval in seconds between two progress charaters
1031 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
1032 self
.PromptMessage
= OpenMessage
1033 self
.CodaMessage
= CloseMessage
1034 self
.ProgressChar
= ProgressChar
1035 self
.Interval
= Interval
1036 if Progressor
._StopFlag
== None:
1037 Progressor
._StopFlag
= threading
.Event()
1039 ## Start to print progress charater
1041 # @param OpenMessage The string printed before progress charaters
1043 def Start(self
, OpenMessage
=None):
1044 if OpenMessage
!= None:
1045 self
.PromptMessage
= OpenMessage
1046 Progressor
._StopFlag
.clear()
1047 if Progressor
._ProgressThread
== None:
1048 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
1049 Progressor
._ProgressThread
.setDaemon(False)
1050 Progressor
._ProgressThread
.start()
1052 ## Stop printing progress charater
1054 # @param CloseMessage The string printed after progress charaters
1056 def Stop(self
, CloseMessage
=None):
1057 OriginalCodaMessage
= self
.CodaMessage
1058 if CloseMessage
!= None:
1059 self
.CodaMessage
= CloseMessage
1061 self
.CodaMessage
= OriginalCodaMessage
1063 ## Thread entry method
1064 def _ProgressThreadEntry(self
):
1065 sys
.stdout
.write(self
.PromptMessage
+ " ")
1068 while not Progressor
._StopFlag
.isSet():
1070 sys
.stdout
.write(self
.ProgressChar
)
1072 TimeUp
= self
.Interval
1073 time
.sleep(self
._CheckInterval
)
1074 TimeUp
-= self
._CheckInterval
1075 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
1078 ## Abort the progress display
1081 if Progressor
._StopFlag
!= None:
1082 Progressor
._StopFlag
.set()
1083 if Progressor
._ProgressThread
!= None:
1084 Progressor
._ProgressThread
.join()
1085 Progressor
._ProgressThread
= None
1087 ## A dict which can access its keys and/or values orderly
1089 # The class implements a new kind of dict which its keys or values can be
1090 # accessed in the order they are added into the dict. It guarantees the order
1091 # by making use of an internal list to keep a copy of keys.
1093 class sdict(IterableUserDict
):
1096 IterableUserDict
.__init
__(self
)
1100 def __setitem__(self
, key
, value
):
1101 if key
not in self
._key
_list
:
1102 self
._key
_list
.append(key
)
1103 IterableUserDict
.__setitem
__(self
, key
, value
)
1106 def __delitem__(self
, key
):
1107 self
._key
_list
.remove(key
)
1108 IterableUserDict
.__delitem
__(self
, key
)
1110 ## used in "for k in dict" loop to ensure the correct order
1112 return self
.iterkeys()
1116 return len(self
._key
_list
)
1118 ## "in" test support
1119 def __contains__(self
, key
):
1120 return key
in self
._key
_list
1123 def index(self
, key
):
1124 return self
._key
_list
.index(key
)
1127 def insert(self
, key
, newkey
, newvalue
, order
):
1128 index
= self
._key
_list
.index(key
)
1129 if order
== 'BEFORE':
1130 self
._key
_list
.insert(index
, newkey
)
1131 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1132 elif order
== 'AFTER':
1133 self
._key
_list
.insert(index
+ 1, newkey
)
1134 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1137 def append(self
, sdict
):
1139 if key
not in self
._key
_list
:
1140 self
._key
_list
.append(key
)
1141 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
1143 def has_key(self
, key
):
1144 return key
in self
._key
_list
1149 IterableUserDict
.clear(self
)
1151 ## Return a copy of keys
1154 for key
in self
._key
_list
:
1158 ## Return a copy of values
1161 for key
in self
._key
_list
:
1162 values
.append(self
[key
])
1165 ## Return a copy of (key, value) list
1168 for key
in self
._key
_list
:
1169 items
.append((key
, self
[key
]))
1172 ## Iteration support
1173 def iteritems(self
):
1174 return iter(self
.items())
1176 ## Keys interation support
1178 return iter(self
.keys())
1180 ## Values interation support
1181 def itervalues(self
):
1182 return iter(self
.values())
1184 ## Return value related to a key, and remove the (key, value) from the dict
1185 def pop(self
, key
, *dv
):
1187 if key
in self
._key
_list
:
1189 self
.__delitem
__(key
)
1194 ## Return (key, value) pair, and remove the (key, value) from the dict
1196 key
= self
._key
_list
[-1]
1198 self
.__delitem
__(key
)
1201 def update(self
, dict=None, **kwargs
):
1203 for k
, v
in dict.items():
1206 for k
, v
in kwargs
.items():
1209 ## Dictionary with restricted keys
1213 def __init__(self
, KeyList
):
1215 dict.__setitem
__(self
, Key
, "")
1218 def __setitem__(self
, key
, value
):
1220 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1221 ExtraData
=", ".join(dict.keys(self
)))
1222 dict.__setitem
__(self
, key
, value
)
1225 def __getitem__(self
, key
):
1228 return dict.__getitem
__(self
, key
)
1231 def __delitem__(self
, key
):
1232 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1237 self
.__setitem
__(Key
, "")
1239 ## Return value related to a key, and remove the (key, value) from the dict
1240 def pop(self
, key
, *dv
):
1241 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1243 ## Return (key, value) pair, and remove the (key, value) from the dict
1245 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1247 ## Dictionary using prioritized list as key
1250 _ListType
= type([])
1251 _TupleType
= type(())
1252 _Wildcard
= 'COMMON'
1253 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1255 def __init__(self
, _Single_
=False, _Level_
=2):
1256 self
._Level
_ = _Level_
1258 self
._Single
_ = _Single_
1261 def __getitem__(self
, key
):
1264 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1268 elif self
._Level
_ > 1:
1269 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1272 if self
._Level
_ > 1:
1273 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1275 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1276 FirstKey
= self
._Wildcard
1279 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1281 return self
._GetAllValues
(FirstKey
, RestKeys
)
1283 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1285 #print "%s-%s" % (FirstKey, self._Level_) ,
1286 if self
._Level
_ > 1:
1287 if FirstKey
== self
._Wildcard
:
1288 if FirstKey
in self
.data
:
1289 Value
= self
.data
[FirstKey
][RestKeys
]
1291 for Key
in self
.data
:
1292 Value
= self
.data
[Key
][RestKeys
]
1293 if Value
!= None: break
1295 if FirstKey
in self
.data
:
1296 Value
= self
.data
[FirstKey
][RestKeys
]
1297 if Value
== None and self
._Wildcard
in self
.data
:
1299 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1301 if FirstKey
== self
._Wildcard
:
1302 if FirstKey
in self
.data
:
1303 Value
= self
.data
[FirstKey
]
1305 for Key
in self
.data
:
1306 Value
= self
.data
[Key
]
1307 if Value
!= None: break
1309 if FirstKey
in self
.data
:
1310 Value
= self
.data
[FirstKey
]
1311 elif self
._Wildcard
in self
.data
:
1312 Value
= self
.data
[self
._Wildcard
]
1315 def _GetAllValues(self
, FirstKey
, RestKeys
):
1317 if self
._Level
_ > 1:
1318 if FirstKey
== self
._Wildcard
:
1319 for Key
in self
.data
:
1320 Value
+= self
.data
[Key
][RestKeys
]
1322 if FirstKey
in self
.data
:
1323 Value
+= self
.data
[FirstKey
][RestKeys
]
1324 if self
._Wildcard
in self
.data
:
1325 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1327 if FirstKey
== self
._Wildcard
:
1328 for Key
in self
.data
:
1329 Value
.append(self
.data
[Key
])
1331 if FirstKey
in self
.data
:
1332 Value
.append(self
.data
[FirstKey
])
1333 if self
._Wildcard
in self
.data
:
1334 Value
.append(self
.data
[self
._Wildcard
])
1338 def __setitem__(self
, key
, value
):
1341 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1346 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1349 if self
._Level
_ > 1:
1350 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1352 if FirstKey
in self
._ValidWildcardList
:
1353 FirstKey
= self
._Wildcard
1355 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1356 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1358 if self
._Level
_ > 1:
1359 self
.data
[FirstKey
][RestKeys
] = value
1361 self
.data
[FirstKey
] = value
1363 def SetGreedyMode(self
):
1364 self
._Single
_ = False
1365 if self
._Level
_ > 1:
1366 for Key
in self
.data
:
1367 self
.data
[Key
].SetGreedyMode()
1369 def SetSingleMode(self
):
1370 self
._Single
_ = True
1371 if self
._Level
_ > 1:
1372 for Key
in self
.data
:
1373 self
.data
[Key
].SetSingleMode()
1375 def GetKeys(self
, KeyIndex
=0):
1376 assert KeyIndex
>= 0
1378 return set(self
.data
.keys())
1381 for Key
in self
.data
:
1382 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1385 ## Boolean chain list
1387 class Blist(UserList
):
1388 def __init__(self
, initlist
=None):
1389 UserList
.__init
__(self
, initlist
)
1390 def __setitem__(self
, i
, item
):
1391 if item
not in [True, False]:
1397 def _GetResult(self
):
1399 for item
in self
.data
:
1402 Result
= property(_GetResult
)
1404 def ParseConsoleLog(Filename
):
1405 Opr
= open(os
.path
.normpath(Filename
), 'r')
1406 Opw
= open(os
.path
.normpath(Filename
+ '.New'), 'w+')
1407 for Line
in Opr
.readlines():
1408 if Line
.find('.efi') > -1:
1409 Line
= Line
[Line
.rfind(' ') : Line
.rfind('.efi')].strip()
1410 Opw
.write('%s\n' % Line
)
1415 def AnalyzePcdExpression(Setting
):
1416 Setting
= Setting
.strip()
1417 # There might be escaped quote in a string: \", \\\"
1418 Data
= Setting
.replace('\\\\', '//').replace('\\\"', '\\\'')
1419 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1426 elif ch
== '(' and not InStr
:
1428 elif ch
== ')' and not InStr
:
1431 if (Pair
> 0 or InStr
) and ch
== TAB_VALUE_SPLIT
:
1438 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1440 FieldList
.append(Setting
[StartPos
:].strip())
1442 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1449 # Analyze DSC PCD value, since there is no data type info in DSC
1450 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1451 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1452 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1453 # 3. Dynamic default:
1454 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1455 # TokenSpace.PcdCName|PcdValue
1457 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1458 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1460 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1461 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1462 # there might have "|" operator, also in string value.
1464 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1465 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1466 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1468 # ValueList: A List contain fields described above
1469 # IsValid: True if conforming EBNF, otherwise False
1470 # Index: The index where PcdValue is in ValueList
1472 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1473 FieldList
= AnalyzePcdExpression(Setting
)
1476 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1477 Value
= FieldList
[0]
1479 if len(FieldList
) > 1:
1481 # Fix the PCD type when no DataType input
1486 if len(FieldList
) > 2:
1488 if DataType
== 'VOID*':
1489 IsValid
= (len(FieldList
) <= 3)
1491 IsValid
= (len(FieldList
) <= 1)
1492 return [Value
, '', Size
], IsValid
, 0
1493 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1494 Value
= FieldList
[0]
1496 if len(FieldList
) > 1:
1500 if len(FieldList
) > 2:
1504 if Value
.startswith("L"):
1505 Size
= str((len(Value
)- 3 + 1) * 2)
1506 elif Value
.startswith("{"):
1507 Size
= str(len(Value
.split(",")))
1509 Size
= str(len(Value
) -2 + 1 )
1510 if DataType
== 'VOID*':
1511 IsValid
= (len(FieldList
) <= 3)
1513 IsValid
= (len(FieldList
) <= 1)
1514 return [Value
, Type
, Size
], IsValid
, 0
1515 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1516 VpdOffset
= FieldList
[0]
1518 if not DataType
== 'VOID*':
1519 if len(FieldList
) > 1:
1520 Value
= FieldList
[1]
1522 if len(FieldList
) > 1:
1524 if len(FieldList
) > 2:
1525 Value
= FieldList
[2]
1526 if DataType
== 'VOID*':
1527 IsValid
= (len(FieldList
) <= 3)
1529 IsValid
= (len(FieldList
) <= 2)
1530 return [VpdOffset
, Size
, Value
], IsValid
, 2
1531 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1532 HiiString
= FieldList
[0]
1533 Guid
= Offset
= Value
= Attribute
= ''
1534 if len(FieldList
) > 1:
1536 if len(FieldList
) > 2:
1537 Offset
= FieldList
[2]
1538 if len(FieldList
) > 3:
1539 Value
= FieldList
[3]
1540 if len(FieldList
) > 4:
1541 Attribute
= FieldList
[4]
1542 IsValid
= (3 <= len(FieldList
) <= 5)
1543 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1548 # Analyze the pcd Value, Datum type and TokenNumber.
1549 # Used to avoid split issue while the value string contain "|" character
1551 # @param[in] Setting: A String contain value/datum type/token number information;
1553 # @retval ValueList: A List contain value, datum type and toke number.
1555 def AnalyzePcdData(Setting
):
1556 ValueList
= ['', '', '']
1558 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1559 PtrValue
= ValueRe
.findall(Setting
)
1561 ValueUpdateFlag
= False
1563 if len(PtrValue
) >= 1:
1564 Setting
= re
.sub(ValueRe
, '', Setting
)
1565 ValueUpdateFlag
= True
1567 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1568 ValueList
[0:len(TokenList
)] = TokenList
1571 ValueList
[0] = PtrValue
[0]
1575 ## AnalyzeHiiPcdData
1577 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1578 # Used to avoid split issue while the value string contain "|" character
1580 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1582 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1584 def AnalyzeHiiPcdData(Setting
):
1585 ValueList
= ['', '', '', '']
1587 TokenList
= GetSplitValueList(Setting
)
1588 ValueList
[0:len(TokenList
)] = TokenList
1592 ## AnalyzeVpdPcdData
1594 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1595 # Used to avoid split issue while the value string contain "|" character
1597 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1599 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1601 def AnalyzeVpdPcdData(Setting
):
1602 ValueList
= ['', '', '']
1604 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1605 PtrValue
= ValueRe
.findall(Setting
)
1607 ValueUpdateFlag
= False
1609 if len(PtrValue
) >= 1:
1610 Setting
= re
.sub(ValueRe
, '', Setting
)
1611 ValueUpdateFlag
= True
1613 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1614 ValueList
[0:len(TokenList
)] = TokenList
1617 ValueList
[2] = PtrValue
[0]
1621 ## check format of PCD value against its the datum type
1623 # For PCD value setting
1625 def CheckPcdDatum(Type
, Value
):
1627 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1628 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1629 or (Value
.startswith('{') and Value
.endswith('}'))
1631 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1632 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1633 elif ValueRe
.match(Value
):
1634 # Check the chars in UnicodeString or CString is printable
1635 if Value
.startswith("L"):
1639 Printset
= set(string
.printable
)
1640 Printset
.remove(TAB_PRINTCHAR_VT
)
1641 Printset
.add(TAB_PRINTCHAR_BS
)
1642 Printset
.add(TAB_PRINTCHAR_NUL
)
1643 if not set(Value
).issubset(Printset
):
1644 PrintList
= list(Printset
)
1646 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1647 elif Type
== 'BOOLEAN':
1648 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1649 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1650 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1651 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1653 Value
= long(Value
, 0)
1655 return False, "Invalid value [%s] of type [%s];"\
1656 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1658 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type
)
1662 ## Split command line option string to list
1664 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1665 # in non-windows platform to launch command
1667 def SplitOption(OptionString
):
1672 for Index
in range(0, len(OptionString
)):
1673 CurrentChar
= OptionString
[Index
]
1674 if CurrentChar
in ['"', "'"]:
1675 if QuotationMark
== CurrentChar
:
1677 elif QuotationMark
== "":
1678 QuotationMark
= CurrentChar
1683 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1684 if Index
> OptionStart
:
1685 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1687 LastChar
= CurrentChar
1688 OptionList
.append(OptionString
[OptionStart
:])
1691 def CommonPath(PathList
):
1692 P1
= min(PathList
).split(os
.path
.sep
)
1693 P2
= max(PathList
).split(os
.path
.sep
)
1694 for Index
in xrange(min(len(P1
), len(P2
))):
1695 if P1
[Index
] != P2
[Index
]:
1696 return os
.path
.sep
.join(P1
[:Index
])
1697 return os
.path
.sep
.join(P1
)
1700 # Convert string to C format array
1702 def ConvertStringToByteArray(Value
):
1703 Value
= Value
.strip()
1707 if not Value
.endswith('}'):
1709 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1710 ValFields
= Value
.split(',')
1712 for Index
in range(len(ValFields
)):
1713 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1716 Value
= '{' + ','.join(ValFields
) + '}'
1720 if Value
.startswith('L"'):
1721 if not Value
.endswith('"'):
1725 elif not Value
.startswith('"') or not Value
.endswith('"'):
1728 Value
= eval(Value
) # translate escape character
1730 for Index
in range(0,len(Value
)):
1732 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1734 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1735 Value
= NewValue
+ '0}'
1738 class PathClass(object):
1739 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1740 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1742 self
.File
= str(File
)
1743 if os
.path
.isabs(self
.File
):
1747 self
.Root
= str(Root
)
1748 self
.AlterRoot
= str(AlterRoot
)
1750 # Remove any '.' and '..' in path
1752 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1753 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1754 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1755 # eliminate the side-effect of 'C:'
1756 if self
.Root
[-1] == ':':
1757 self
.Root
+= os
.path
.sep
1758 # file path should not start with path separator
1759 if self
.Root
[-1] == os
.path
.sep
:
1760 self
.File
= self
.Path
[len(self
.Root
):]
1762 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1764 self
.Path
= os
.path
.normpath(self
.File
)
1766 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1767 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1771 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1773 self
.Dir
= self
.Root
1775 self
.Dir
= self
.SubDir
1780 self
.Type
= self
.Ext
.lower()
1782 self
.IsBinary
= IsBinary
1783 self
.Target
= Target
1784 self
.TagName
= TagName
1785 self
.ToolCode
= ToolCode
1786 self
.ToolChainFamily
= ToolChainFamily
1790 ## Convert the object of this class to a string
1792 # Convert member Path of the class to a string
1794 # @retval string Formatted String
1799 ## Override __eq__ function
1801 # Check whether PathClass are the same
1803 # @retval False The two PathClass are different
1804 # @retval True The two PathClass are the same
1806 def __eq__(self
, Other
):
1807 if type(Other
) == type(self
):
1808 return self
.Path
== Other
.Path
1810 return self
.Path
== str(Other
)
1812 ## Override __cmp__ function
1814 # Customize the comparsion operation of two PathClass
1816 # @retval 0 The two PathClass are different
1817 # @retval -1 The first PathClass is less than the second PathClass
1818 # @retval 1 The first PathClass is Bigger than the second PathClass
1819 def __cmp__(self
, Other
):
1820 if type(Other
) == type(self
):
1821 OtherKey
= Other
.Path
1823 OtherKey
= str(Other
)
1826 if SelfKey
== OtherKey
:
1828 elif SelfKey
> OtherKey
:
1833 ## Override __hash__ function
1835 # Use Path as key in hash table
1837 # @retval string Key for hash table
1840 return hash(self
.Path
)
1842 def _GetFileKey(self
):
1843 if self
._Key
== None:
1844 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1847 def _GetTimeStamp(self
):
1848 return os
.stat(self
.Path
)[8]
1850 def Validate(self
, Type
='', CaseSensitive
=True):
1851 if GlobalData
.gCaseInsensitive
:
1852 CaseSensitive
= False
1853 if Type
and Type
.lower() != self
.Type
:
1854 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1856 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1857 if not RealRoot
and not RealFile
:
1858 RealFile
= self
.File
1860 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1862 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1863 if len (mws
.getPkgPath()) == 0:
1864 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1866 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1870 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1871 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1872 ErrorCode
= FILE_CASE_MISMATCH
1873 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1875 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1876 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1878 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1881 self
.File
= RealFile
1882 self
.Root
= RealRoot
1883 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1884 return ErrorCode
, ErrorInfo
1886 Key
= property(_GetFileKey
)
1887 TimeStamp
= property(_GetTimeStamp
)
1889 ## Parse PE image to get the required PE informaion.
1891 class PeImageClass():
1894 # @param File FilePath of PeImage
1896 def __init__(self
, PeFile
):
1897 self
.FileName
= PeFile
1898 self
.IsValid
= False
1901 self
.SectionAlignment
= 0
1902 self
.SectionHeaderList
= []
1905 PeObject
= open(PeFile
, 'rb')
1907 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1910 ByteArray
= array
.array('B')
1911 ByteArray
.fromfile(PeObject
, 0x3E)
1912 ByteList
= ByteArray
.tolist()
1913 # DOS signature should be 'MZ'
1914 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1915 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1918 # Read 4 byte PE Signature
1919 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1920 PeObject
.seek(PeOffset
)
1921 ByteArray
= array
.array('B')
1922 ByteArray
.fromfile(PeObject
, 4)
1923 # PE signature should be 'PE\0\0'
1924 if ByteArray
.tostring() != 'PE\0\0':
1925 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1928 # Read PE file header
1929 ByteArray
= array
.array('B')
1930 ByteArray
.fromfile(PeObject
, 0x14)
1931 ByteList
= ByteArray
.tolist()
1932 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1934 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1937 # Read PE optional header
1938 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1939 ByteArray
= array
.array('B')
1940 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1941 ByteList
= ByteArray
.tolist()
1942 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1943 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1944 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1946 # Read each Section Header
1947 for Index
in range(SecNumber
):
1948 ByteArray
= array
.array('B')
1949 ByteArray
.fromfile(PeObject
, 0x28)
1950 ByteList
= ByteArray
.tolist()
1951 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1952 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1953 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1954 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1955 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1959 def _ByteListToStr(self
, ByteList
):
1961 for index
in range(len(ByteList
)):
1962 if ByteList
[index
] == 0:
1964 String
+= chr(ByteList
[index
])
1967 def _ByteListToInt(self
, ByteList
):
1969 for index
in range(len(ByteList
) - 1, -1, -1):
1970 Value
= (Value
<< 8) |
int(ByteList
[index
])
1980 def __init__(self
,SkuIdentifier
='', SkuIds
={}):
1982 self
.AvailableSkuIds
= sdict()
1984 self
.SkuIdNumberSet
= []
1985 if SkuIdentifier
== '' or SkuIdentifier
is None:
1986 self
.SkuIdSet
= ['DEFAULT']
1987 self
.SkuIdNumberSet
= ['0U']
1988 elif SkuIdentifier
== 'ALL':
1989 self
.SkuIdSet
= SkuIds
.keys()
1990 self
.SkuIdNumberSet
= [num
.strip() + 'U' for num
in SkuIds
.values()]
1992 r
= SkuIdentifier
.split('|')
1993 self
.SkuIdSet
=[r
[k
].strip() for k
in range(len(r
))]
1996 self
.SkuIdNumberSet
= [SkuIds
[k
].strip() + 'U' for k
in self
.SkuIdSet
]
1998 EdkLogger
.error("build", PARAMETER_INVALID
,
1999 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
2000 % (k
, " ".join(SkuIds
.keys())))
2001 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
and SkuIdentifier
!= 'ALL':
2002 self
.SkuIdSet
.remove('DEFAULT')
2003 self
.SkuIdNumberSet
.remove('0U')
2004 for each
in self
.SkuIdSet
:
2006 self
.AvailableSkuIds
[each
] = SkuIds
[each
]
2008 EdkLogger
.error("build", PARAMETER_INVALID
,
2009 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
2010 % (each
, " ".join(SkuIds
.keys())))
2012 def __SkuUsageType(self
):
2014 if len(self
.SkuIdSet
) == 1:
2015 if self
.SkuIdSet
[0] == 'DEFAULT':
2016 return SkuClass
.DEFAULT
2018 return SkuClass
.SINGLE
2020 return SkuClass
.MULTIPLE
2022 def __GetAvailableSkuIds(self
):
2023 return self
.AvailableSkuIds
2025 def __GetSystemSkuID(self
):
2026 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2027 return self
.SkuIdSet
[0]
2030 def __GetAvailableSkuIdNumber(self
):
2031 return self
.SkuIdNumberSet
2032 SystemSkuId
= property(__GetSystemSkuID
)
2033 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2034 SkuUsageType
= property(__SkuUsageType
)
2035 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2038 # Pack a registry format GUID
2040 def PackRegistryFormatGuid(Guid
):
2041 Guid
= Guid
.split('-')
2042 return pack('=LHHBBBBBBBB',
2046 int(Guid
[3][-4:-2], 16),
2047 int(Guid
[3][-2:], 16),
2048 int(Guid
[4][-12:-10], 16),
2049 int(Guid
[4][-10:-8], 16),
2050 int(Guid
[4][-8:-6], 16),
2051 int(Guid
[4][-6:-4], 16),
2052 int(Guid
[4][-4:-2], 16),
2053 int(Guid
[4][-2:], 16)
2058 # This acts like the main() function for the script, unless it is 'import'ed into another
2061 if __name__
== '__main__':