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
)
1417 # Analyze DSC PCD value, since there is no data type info in DSC
1418 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1419 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1420 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1421 # 3. Dynamic default:
1422 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1423 # TokenSpace.PcdCName|PcdValue
1425 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1426 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1428 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1429 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1430 # there might have "|" operator, also in string value.
1432 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1433 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1434 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1436 # ValueList: A List contain fields described above
1437 # IsValid: True if conforming EBNF, otherwise False
1438 # Index: The index where PcdValue is in ValueList
1440 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1441 Setting
= Setting
.strip()
1442 # There might be escaped quote in a string: \", \\\"
1443 Data
= Setting
.replace('\\\\', '//').replace('\\\"', '\\\'')
1444 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1451 elif ch
== '(' and not InStr
:
1453 elif ch
== ')' and not InStr
:
1456 if (Pair
> 0 or InStr
) and ch
== TAB_VALUE_SPLIT
:
1463 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1465 FieldList
.append(Setting
[StartPos
:].strip())
1467 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1471 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1472 Value
= FieldList
[0]
1474 if len(FieldList
) > 1:
1476 # Fix the PCD type when no DataType input
1481 if len(FieldList
) > 2:
1483 if DataType
== 'VOID*':
1484 IsValid
= (len(FieldList
) <= 3)
1486 IsValid
= (len(FieldList
) <= 1)
1487 return [Value
, '', Size
], IsValid
, 0
1488 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1489 Value
= FieldList
[0]
1491 if len(FieldList
) > 1:
1495 if len(FieldList
) > 2:
1499 if Value
.startswith("L"):
1500 Size
= str((len(Value
)- 3 + 1) * 2)
1501 elif Value
.startswith("{"):
1502 Size
= str(len(Value
.split(",")))
1504 Size
= str(len(Value
) -2 + 1 )
1505 if DataType
== 'VOID*':
1506 IsValid
= (len(FieldList
) <= 3)
1508 IsValid
= (len(FieldList
) <= 1)
1509 return [Value
, Type
, Size
], IsValid
, 0
1510 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1511 VpdOffset
= FieldList
[0]
1513 if not DataType
== 'VOID*':
1514 if len(FieldList
) > 1:
1515 Value
= FieldList
[1]
1517 if len(FieldList
) > 1:
1519 if len(FieldList
) > 2:
1520 Value
= FieldList
[2]
1521 if DataType
== 'VOID*':
1522 IsValid
= (len(FieldList
) <= 3)
1524 IsValid
= (len(FieldList
) <= 2)
1525 return [VpdOffset
, Size
, Value
], IsValid
, 2
1526 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1527 HiiString
= FieldList
[0]
1528 Guid
= Offset
= Value
= Attribute
= ''
1529 if len(FieldList
) > 1:
1531 if len(FieldList
) > 2:
1532 Offset
= FieldList
[2]
1533 if len(FieldList
) > 3:
1534 Value
= FieldList
[3]
1535 if len(FieldList
) > 4:
1536 Attribute
= FieldList
[4]
1537 IsValid
= (3 <= len(FieldList
) <= 5)
1538 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1543 # Analyze the pcd Value, Datum type and TokenNumber.
1544 # Used to avoid split issue while the value string contain "|" character
1546 # @param[in] Setting: A String contain value/datum type/token number information;
1548 # @retval ValueList: A List contain value, datum type and toke number.
1550 def AnalyzePcdData(Setting
):
1551 ValueList
= ['', '', '']
1553 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1554 PtrValue
= ValueRe
.findall(Setting
)
1556 ValueUpdateFlag
= False
1558 if len(PtrValue
) >= 1:
1559 Setting
= re
.sub(ValueRe
, '', Setting
)
1560 ValueUpdateFlag
= True
1562 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1563 ValueList
[0:len(TokenList
)] = TokenList
1566 ValueList
[0] = PtrValue
[0]
1570 ## AnalyzeHiiPcdData
1572 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1573 # Used to avoid split issue while the value string contain "|" character
1575 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1577 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1579 def AnalyzeHiiPcdData(Setting
):
1580 ValueList
= ['', '', '', '']
1582 TokenList
= GetSplitValueList(Setting
)
1583 ValueList
[0:len(TokenList
)] = TokenList
1587 ## AnalyzeVpdPcdData
1589 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1590 # Used to avoid split issue while the value string contain "|" character
1592 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1594 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1596 def AnalyzeVpdPcdData(Setting
):
1597 ValueList
= ['', '', '']
1599 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1600 PtrValue
= ValueRe
.findall(Setting
)
1602 ValueUpdateFlag
= False
1604 if len(PtrValue
) >= 1:
1605 Setting
= re
.sub(ValueRe
, '', Setting
)
1606 ValueUpdateFlag
= True
1608 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1609 ValueList
[0:len(TokenList
)] = TokenList
1612 ValueList
[2] = PtrValue
[0]
1616 ## check format of PCD value against its the datum type
1618 # For PCD value setting
1620 def CheckPcdDatum(Type
, Value
):
1622 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1623 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1624 or (Value
.startswith('{') and Value
.endswith('}'))
1626 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1627 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1628 elif ValueRe
.match(Value
):
1629 # Check the chars in UnicodeString or CString is printable
1630 if Value
.startswith("L"):
1634 Printset
= set(string
.printable
)
1635 Printset
.remove(TAB_PRINTCHAR_VT
)
1636 Printset
.add(TAB_PRINTCHAR_BS
)
1637 Printset
.add(TAB_PRINTCHAR_NUL
)
1638 if not set(Value
).issubset(Printset
):
1639 PrintList
= list(Printset
)
1641 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1642 elif Type
== 'BOOLEAN':
1643 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1644 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1645 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1646 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1648 Value
= long(Value
, 0)
1650 return False, "Invalid value [%s] of type [%s];"\
1651 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1653 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type
)
1657 ## Split command line option string to list
1659 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1660 # in non-windows platform to launch command
1662 def SplitOption(OptionString
):
1667 for Index
in range(0, len(OptionString
)):
1668 CurrentChar
= OptionString
[Index
]
1669 if CurrentChar
in ['"', "'"]:
1670 if QuotationMark
== CurrentChar
:
1672 elif QuotationMark
== "":
1673 QuotationMark
= CurrentChar
1678 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1679 if Index
> OptionStart
:
1680 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1682 LastChar
= CurrentChar
1683 OptionList
.append(OptionString
[OptionStart
:])
1686 def CommonPath(PathList
):
1687 P1
= min(PathList
).split(os
.path
.sep
)
1688 P2
= max(PathList
).split(os
.path
.sep
)
1689 for Index
in xrange(min(len(P1
), len(P2
))):
1690 if P1
[Index
] != P2
[Index
]:
1691 return os
.path
.sep
.join(P1
[:Index
])
1692 return os
.path
.sep
.join(P1
)
1695 # Convert string to C format array
1697 def ConvertStringToByteArray(Value
):
1698 Value
= Value
.strip()
1702 if not Value
.endswith('}'):
1704 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1705 ValFields
= Value
.split(',')
1707 for Index
in range(len(ValFields
)):
1708 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1711 Value
= '{' + ','.join(ValFields
) + '}'
1715 if Value
.startswith('L"'):
1716 if not Value
.endswith('"'):
1720 elif not Value
.startswith('"') or not Value
.endswith('"'):
1723 Value
= eval(Value
) # translate escape character
1725 for Index
in range(0,len(Value
)):
1727 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1729 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1730 Value
= NewValue
+ '0}'
1733 class PathClass(object):
1734 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1735 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1737 self
.File
= str(File
)
1738 if os
.path
.isabs(self
.File
):
1742 self
.Root
= str(Root
)
1743 self
.AlterRoot
= str(AlterRoot
)
1745 # Remove any '.' and '..' in path
1747 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1748 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1749 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1750 # eliminate the side-effect of 'C:'
1751 if self
.Root
[-1] == ':':
1752 self
.Root
+= os
.path
.sep
1753 # file path should not start with path separator
1754 if self
.Root
[-1] == os
.path
.sep
:
1755 self
.File
= self
.Path
[len(self
.Root
):]
1757 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1759 self
.Path
= os
.path
.normpath(self
.File
)
1761 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1762 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1766 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1768 self
.Dir
= self
.Root
1770 self
.Dir
= self
.SubDir
1775 self
.Type
= self
.Ext
.lower()
1777 self
.IsBinary
= IsBinary
1778 self
.Target
= Target
1779 self
.TagName
= TagName
1780 self
.ToolCode
= ToolCode
1781 self
.ToolChainFamily
= ToolChainFamily
1785 ## Convert the object of this class to a string
1787 # Convert member Path of the class to a string
1789 # @retval string Formatted String
1794 ## Override __eq__ function
1796 # Check whether PathClass are the same
1798 # @retval False The two PathClass are different
1799 # @retval True The two PathClass are the same
1801 def __eq__(self
, Other
):
1802 if type(Other
) == type(self
):
1803 return self
.Path
== Other
.Path
1805 return self
.Path
== str(Other
)
1807 ## Override __cmp__ function
1809 # Customize the comparsion operation of two PathClass
1811 # @retval 0 The two PathClass are different
1812 # @retval -1 The first PathClass is less than the second PathClass
1813 # @retval 1 The first PathClass is Bigger than the second PathClass
1814 def __cmp__(self
, Other
):
1815 if type(Other
) == type(self
):
1816 OtherKey
= Other
.Path
1818 OtherKey
= str(Other
)
1821 if SelfKey
== OtherKey
:
1823 elif SelfKey
> OtherKey
:
1828 ## Override __hash__ function
1830 # Use Path as key in hash table
1832 # @retval string Key for hash table
1835 return hash(self
.Path
)
1837 def _GetFileKey(self
):
1838 if self
._Key
== None:
1839 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1842 def _GetTimeStamp(self
):
1843 return os
.stat(self
.Path
)[8]
1845 def Validate(self
, Type
='', CaseSensitive
=True):
1846 if GlobalData
.gCaseInsensitive
:
1847 CaseSensitive
= False
1848 if Type
and Type
.lower() != self
.Type
:
1849 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1851 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1852 if not RealRoot
and not RealFile
:
1853 RealFile
= self
.File
1855 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1857 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1858 if len (mws
.getPkgPath()) == 0:
1859 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1861 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1865 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1866 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1867 ErrorCode
= FILE_CASE_MISMATCH
1868 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1870 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1871 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1873 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1876 self
.File
= RealFile
1877 self
.Root
= RealRoot
1878 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1879 return ErrorCode
, ErrorInfo
1881 Key
= property(_GetFileKey
)
1882 TimeStamp
= property(_GetTimeStamp
)
1884 ## Parse PE image to get the required PE informaion.
1886 class PeImageClass():
1889 # @param File FilePath of PeImage
1891 def __init__(self
, PeFile
):
1892 self
.FileName
= PeFile
1893 self
.IsValid
= False
1896 self
.SectionAlignment
= 0
1897 self
.SectionHeaderList
= []
1900 PeObject
= open(PeFile
, 'rb')
1902 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1905 ByteArray
= array
.array('B')
1906 ByteArray
.fromfile(PeObject
, 0x3E)
1907 ByteList
= ByteArray
.tolist()
1908 # DOS signature should be 'MZ'
1909 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1910 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1913 # Read 4 byte PE Signature
1914 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1915 PeObject
.seek(PeOffset
)
1916 ByteArray
= array
.array('B')
1917 ByteArray
.fromfile(PeObject
, 4)
1918 # PE signature should be 'PE\0\0'
1919 if ByteArray
.tostring() != 'PE\0\0':
1920 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1923 # Read PE file header
1924 ByteArray
= array
.array('B')
1925 ByteArray
.fromfile(PeObject
, 0x14)
1926 ByteList
= ByteArray
.tolist()
1927 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1929 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1932 # Read PE optional header
1933 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1934 ByteArray
= array
.array('B')
1935 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1936 ByteList
= ByteArray
.tolist()
1937 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1938 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1939 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1941 # Read each Section Header
1942 for Index
in range(SecNumber
):
1943 ByteArray
= array
.array('B')
1944 ByteArray
.fromfile(PeObject
, 0x28)
1945 ByteList
= ByteArray
.tolist()
1946 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1947 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1948 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1949 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1950 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1954 def _ByteListToStr(self
, ByteList
):
1956 for index
in range(len(ByteList
)):
1957 if ByteList
[index
] == 0:
1959 String
+= chr(ByteList
[index
])
1962 def _ByteListToInt(self
, ByteList
):
1964 for index
in range(len(ByteList
) - 1, -1, -1):
1965 Value
= (Value
<< 8) |
int(ByteList
[index
])
1975 def __init__(self
,SkuIdentifier
='', SkuIds
={}):
1977 self
.AvailableSkuIds
= sdict()
1979 self
.SkuIdNumberSet
= []
1980 if SkuIdentifier
== '' or SkuIdentifier
is None:
1981 self
.SkuIdSet
= ['DEFAULT']
1982 self
.SkuIdNumberSet
= ['0U']
1983 elif SkuIdentifier
== 'ALL':
1984 self
.SkuIdSet
= SkuIds
.keys()
1985 self
.SkuIdNumberSet
= [num
.strip() + 'U' for num
in SkuIds
.values()]
1987 r
= SkuIdentifier
.split('|')
1988 self
.SkuIdSet
=[r
[k
].strip() for k
in range(len(r
))]
1991 self
.SkuIdNumberSet
= [SkuIds
[k
].strip() + 'U' for k
in self
.SkuIdSet
]
1993 EdkLogger
.error("build", PARAMETER_INVALID
,
1994 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1995 % (k
, " ".join(SkuIds
.keys())))
1996 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
and SkuIdentifier
!= 'ALL':
1997 self
.SkuIdSet
.remove('DEFAULT')
1998 self
.SkuIdNumberSet
.remove('0U')
1999 for each
in self
.SkuIdSet
:
2001 self
.AvailableSkuIds
[each
] = SkuIds
[each
]
2003 EdkLogger
.error("build", PARAMETER_INVALID
,
2004 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
2005 % (each
, " ".join(SkuIds
.keys())))
2007 def __SkuUsageType(self
):
2009 if len(self
.SkuIdSet
) == 1:
2010 if self
.SkuIdSet
[0] == 'DEFAULT':
2011 return SkuClass
.DEFAULT
2013 return SkuClass
.SINGLE
2015 return SkuClass
.MULTIPLE
2017 def __GetAvailableSkuIds(self
):
2018 return self
.AvailableSkuIds
2020 def __GetSystemSkuID(self
):
2021 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2022 return self
.SkuIdSet
[0]
2025 def __GetAvailableSkuIdNumber(self
):
2026 return self
.SkuIdNumberSet
2027 SystemSkuId
= property(__GetSystemSkuID
)
2028 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2029 SkuUsageType
= property(__SkuUsageType
)
2030 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2033 # Pack a registry format GUID
2035 def PackRegistryFormatGuid(Guid
):
2036 Guid
= Guid
.split('-')
2037 return pack('=LHHBBBBBBBB',
2041 int(Guid
[3][-4:-2], 16),
2042 int(Guid
[3][-2:], 16),
2043 int(Guid
[4][-12:-10], 16),
2044 int(Guid
[4][-10:-8], 16),
2045 int(Guid
[4][-8:-6], 16),
2046 int(Guid
[4][-6:-4], 16),
2047 int(Guid
[4][-4:-2], 16),
2048 int(Guid
[4][-2:], 16)
2053 # This acts like the main() function for the script, unless it is 'import'ed into another
2056 if __name__
== '__main__':