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 """
77 for index
, line
in enumerate(lines
):
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(".data.(%s)$" % varname
, line
)
99 m
= re
.match('^([\da-fA-Fx]+) +([\da-fA-Fx]+)', lines
[index
+ 1].strip())
101 varoffset
.append((varname
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
105 # get section information from efi file
106 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
107 if efisecs
== None or len(efisecs
) == 0:
111 for efisec
in efisecs
:
112 for section
in sections
:
113 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
114 redirection
= int(section
[1], 16) - efisec
[1]
117 for var
in varoffset
:
118 for efisec
in efisecs
:
119 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
120 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
123 def _parseGeneral(lines
, efifilepath
, varnames
):
124 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
125 secs
= [] # key = section name
127 secRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
128 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
132 if re
.match("^Start[' ']+Length[' ']+Name[' ']+Class", line
):
135 if re
.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line
):
138 if re
.match("^entry point at", line
):
141 if status
== 1 and len(line
) != 0:
142 m
= secRe
.match(line
)
143 assert m
!= None, "Fail to parse the section in map file , line is %s" % line
144 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
145 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
146 if status
== 2 and len(line
) != 0:
147 for varname
in varnames
:
148 m
= symRe
.match(line
)
149 assert m
!= None, "Fail to parse the symbol in map file, line is %s" % line
150 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
151 sec_no
= int(sec_no
, 16)
152 sym_offset
= int(sym_offset
, 16)
153 vir_addr
= int(vir_addr
, 16)
154 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
156 # fond a binary pcd entry in map file
158 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
159 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
161 if not varoffset
: return []
163 # get section information from efi file
164 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
165 if efisecs
== None or len(efisecs
) == 0:
169 for var
in varoffset
:
171 for efisec
in efisecs
:
173 if var
[1].strip() == efisec
[0].strip():
174 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
175 elif var
[4] == index
:
176 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
180 ## Routine to process duplicated INF
182 # This function is called by following two cases:
185 # Pkg/module/module.inf
186 # Pkg/module/module.inf {
188 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
191 # INF Pkg/module/module.inf
192 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
194 # This function copies Pkg/module/module.inf to
195 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
197 # @param Path Original PathClass object
198 # @param BaseName New file base name
200 # @retval return the new PathClass object
202 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
203 Filename
= os
.path
.split(Path
.File
)[1]
205 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
207 Filename
= BaseName
+ Path
.BaseName
210 # If -N is specified on command line, cache is disabled
211 # The directory has to be created
213 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
214 if not os
.path
.exists(DbDir
):
217 # A temporary INF is copied to database path which must have write permission
218 # The temporary will be removed at the end of build
219 # In case of name conflict, the file name is
220 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
222 TempFullPath
= os
.path
.join(DbDir
,
224 RtPath
= PathClass(Path
.File
, Workspace
)
226 # Modify the full path to temporary path, keep other unchanged
228 # To build same module more than once, the module path with FILE_GUID overridden has
229 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
230 # in DSC which is used as relative path by C files and other files in INF.
231 # A trick was used: all module paths are PathClass instances, after the initialization
232 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
234 # The reason for creating a temporary INF is:
235 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
236 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
237 # A different key for the same module is needed to create different output directory,
238 # retrieve overridden PCDs, library instances.
240 # The BaseName is the FILE_GUID which is also the output directory name.
243 RtPath
.Path
= TempFullPath
244 RtPath
.BaseName
= BaseName
246 # If file exists, compare contents
248 if os
.path
.exists(TempFullPath
):
249 with
open(str(Path
), 'rb') as f1
: Src
= f1
.read()
250 with
open(TempFullPath
, 'rb') as f2
: Dst
= f2
.read()
253 GlobalData
.gTempInfs
.append(TempFullPath
)
254 shutil
.copy2(str(Path
), TempFullPath
)
257 ## Remove temporary created INFs whose paths were saved in gTempInfs
259 def ClearDuplicatedInf():
260 for File
in GlobalData
.gTempInfs
:
261 if os
.path
.exists(File
):
264 ## callback routine for processing variable option
266 # This function can be used to process variable number of option values. The
267 # typical usage of it is specify architecure list on command line.
268 # (e.g. <tool> -a IA32 X64 IPF)
270 # @param Option Standard callback function parameter
271 # @param OptionString Standard callback function parameter
272 # @param Value Standard callback function parameter
273 # @param Parser Standard callback function parameter
277 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
280 RawArgs
= Parser
.rargs
283 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
284 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
288 setattr(Parser
.values
, Option
.dest
, Value
)
290 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
292 # @param Guid The GUID string
294 # @retval string The GUID string in C structure style
296 def GuidStringToGuidStructureString(Guid
):
297 GuidList
= Guid
.split('-')
299 for Index
in range(0, 3, 1):
300 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
301 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
302 for Index
in range(0, 12, 2):
303 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
307 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
309 # @param GuidValue The GUID value in byte array
311 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
313 def GuidStructureByteArrayToGuidString(GuidValue
):
314 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
315 guidValueList
= guidValueString
.split(",")
316 if len(guidValueList
) != 16:
318 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
320 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
321 int(guidValueList
[3], 16),
322 int(guidValueList
[2], 16),
323 int(guidValueList
[1], 16),
324 int(guidValueList
[0], 16),
325 int(guidValueList
[5], 16),
326 int(guidValueList
[4], 16),
327 int(guidValueList
[7], 16),
328 int(guidValueList
[6], 16),
329 int(guidValueList
[8], 16),
330 int(guidValueList
[9], 16),
331 int(guidValueList
[10], 16),
332 int(guidValueList
[11], 16),
333 int(guidValueList
[12], 16),
334 int(guidValueList
[13], 16),
335 int(guidValueList
[14], 16),
336 int(guidValueList
[15], 16)
341 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
343 # @param GuidValue The GUID value in C structure format
345 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
347 def GuidStructureStringToGuidString(GuidValue
):
348 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
349 guidValueList
= guidValueString
.split(",")
350 if len(guidValueList
) != 11:
352 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
354 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
355 int(guidValueList
[0], 16),
356 int(guidValueList
[1], 16),
357 int(guidValueList
[2], 16),
358 int(guidValueList
[3], 16),
359 int(guidValueList
[4], 16),
360 int(guidValueList
[5], 16),
361 int(guidValueList
[6], 16),
362 int(guidValueList
[7], 16),
363 int(guidValueList
[8], 16),
364 int(guidValueList
[9], 16),
365 int(guidValueList
[10], 16)
370 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
372 # @param GuidValue The GUID value in C structure format
374 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
376 def GuidStructureStringToGuidValueName(GuidValue
):
377 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
378 guidValueList
= guidValueString
.split(",")
379 if len(guidValueList
) != 11:
380 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
381 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
382 int(guidValueList
[0], 16),
383 int(guidValueList
[1], 16),
384 int(guidValueList
[2], 16),
385 int(guidValueList
[3], 16),
386 int(guidValueList
[4], 16),
387 int(guidValueList
[5], 16),
388 int(guidValueList
[6], 16),
389 int(guidValueList
[7], 16),
390 int(guidValueList
[8], 16),
391 int(guidValueList
[9], 16),
392 int(guidValueList
[10], 16)
395 ## Create directories
397 # @param Directory The directory name
399 def CreateDirectory(Directory
):
400 if Directory
== None or Directory
.strip() == "":
403 if not os
.access(Directory
, os
.F_OK
):
404 os
.makedirs(Directory
)
409 ## Remove directories, including files and sub-directories in it
411 # @param Directory The directory name
413 def RemoveDirectory(Directory
, Recursively
=False):
414 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
417 CurrentDirectory
= os
.getcwd()
419 for File
in os
.listdir("."):
420 if os
.path
.isdir(File
):
421 RemoveDirectory(File
, Recursively
)
424 os
.chdir(CurrentDirectory
)
427 ## Check if given file is changed or not
429 # This method is used to check if a file is changed or not between two build
430 # actions. It makes use a cache to store files timestamp.
432 # @param File The path of file
434 # @retval True If the given file is changed, doesn't exist, or can't be
435 # found in timestamp cache
436 # @retval False If the given file is changed
439 if not os
.path
.exists(File
):
442 FileState
= os
.stat(File
)
443 TimeStamp
= FileState
[-2]
445 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
449 gFileTimeStampCache
[File
] = TimeStamp
453 ## Store content in file
455 # This method is used to save file only when its content is changed. This is
456 # quite useful for "make" system to decide what will be re-built and what won't.
458 # @param File The path of file
459 # @param Content The new content of the file
460 # @param IsBinaryFile The flag indicating if the file is binary file or not
462 # @retval True If the file content is changed and the file is renewed
463 # @retval False If the file content is the same
465 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
467 Content
= Content
.replace("\n", os
.linesep
)
469 if os
.path
.exists(File
):
471 if Content
== open(File
, "rb").read():
474 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
476 DirName
= os
.path
.dirname(File
)
477 if not CreateDirectory(DirName
):
478 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
481 DirName
= os
.getcwd()
482 if not os
.access(DirName
, os
.W_OK
):
483 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
486 if GlobalData
.gIsWindows
:
488 from PyUtility
import SaveFileToDisk
489 if not SaveFileToDisk(File
, Content
):
490 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
492 Fd
= open(File
, "wb")
496 Fd
= open(File
, "wb")
500 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
504 ## Make a Python object persistent on file system
506 # @param Data The object to be stored in file
507 # @param File The path of file to store the object
509 def DataDump(Data
, File
):
512 Fd
= open(File
, 'wb')
513 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
515 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
520 ## Restore a Python object from a file
522 # @param File The path of file stored the object
524 # @retval object A python object
525 # @retval None If failure in file operation
527 def DataRestore(File
):
531 Fd
= open(File
, 'rb')
532 Data
= cPickle
.load(Fd
)
534 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
541 ## Retrieve and cache the real path name in file system
543 # @param Root The root directory of path relative to
545 # @retval str The path string if the path exists
546 # @retval None If path doesn't exist
552 def __init__(self
, Root
):
554 for F
in os
.listdir(Root
):
556 self
._UPPER
_CACHE
_[F
.upper()] = F
559 def __getitem__(self
, Path
):
560 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
563 if Path
and Path
[0] == os
.path
.sep
:
565 if Path
in self
._CACHE
_:
566 return os
.path
.join(self
._Root
, Path
)
567 UpperPath
= Path
.upper()
568 if UpperPath
in self
._UPPER
_CACHE
_:
569 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
573 SepIndex
= Path
.find(os
.path
.sep
)
575 Parent
= UpperPath
[:SepIndex
]
576 if Parent
not in self
._UPPER
_CACHE
_:
578 LastSepIndex
= SepIndex
579 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
581 if LastSepIndex
== -1:
586 SepIndex
= LastSepIndex
588 Parent
= Path
[:SepIndex
]
589 ParentKey
= UpperPath
[:SepIndex
]
590 if ParentKey
not in self
._UPPER
_CACHE
_:
594 if Parent
in self
._CACHE
_:
597 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
598 for F
in os
.listdir(ParentDir
):
599 Dir
= os
.path
.join(ParentDir
, F
)
600 self
._CACHE
_.add(Dir
)
601 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
603 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
606 if Path
in self
._CACHE
_:
607 return os
.path
.join(self
._Root
, Path
)
608 elif UpperPath
in self
._UPPER
_CACHE
_:
609 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
612 ## Get all files of a directory
614 # @param Root: Root dir
615 # @param SkipList : The files need be skipped
617 # @retval A list of all files
619 def GetFiles(Root
, SkipList
=None, FullPath
=True):
622 for Root
, Dirs
, Files
in os
.walk(Root
):
624 for Item
in SkipList
:
629 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
631 File
= File
[len(OriPath
) + 1:]
632 FileList
.append(File
)
636 ## Check if gvien file exists or not
638 # @param File File name or path to be checked
639 # @param Dir The directory the file is relative to
641 # @retval True if file exists
642 # @retval False if file doesn't exists
644 def ValidFile(File
, Ext
=None):
646 Dummy
, FileExt
= os
.path
.splitext(File
)
647 if FileExt
.lower() != Ext
.lower():
649 if not os
.path
.exists(File
):
653 def RealPath(File
, Dir
='', OverrideDir
=''):
654 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
655 NewFile
= GlobalData
.gAllFiles
[NewFile
]
656 if not NewFile
and OverrideDir
:
657 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
658 NewFile
= GlobalData
.gAllFiles
[NewFile
]
661 def RealPath2(File
, Dir
='', OverrideDir
=''):
664 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
666 if OverrideDir
[-1] == os
.path
.sep
:
667 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
669 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
670 if GlobalData
.gAllFiles
:
671 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
673 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
674 if not os
.path
.exists(NewFile
):
678 if Dir
[-1] == os
.path
.sep
:
679 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
681 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
687 ## Check if gvien file exists or not
690 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
693 Dummy
, FileExt
= os
.path
.splitext(File
)
694 if FileExt
.lower() != Ext
.lower():
697 # Replace the Edk macros
698 if OverrideDir
!= '' and OverrideDir
!= None:
699 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
700 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
701 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
702 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
704 # Replace the default dir to current dir
707 Dir
= Dir
[len(Workspace
) + 1:]
709 # First check if File has Edk definition itself
710 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
711 NewFile
= File
.replace('$(EFI_SOURCE)', EfiSource
)
712 NewFile
= NewFile
.replace('$(EDK_SOURCE)', EdkSource
)
713 NewFile
= AllFiles
[os
.path
.normpath(NewFile
)]
717 # Second check the path with override value
718 if OverrideDir
!= '' and OverrideDir
!= None:
719 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
723 # Last check the path with normal definitions
724 File
= os
.path
.join(Dir
, File
)
725 NewFile
= AllFiles
[os
.path
.normpath(File
)]
731 ## Check if gvien file exists or not
734 def ValidFile3(AllFiles
, File
, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
735 # Replace the Edk macros
736 if OverrideDir
!= '' and OverrideDir
!= None:
737 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
738 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
739 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
740 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
742 # Replace the default dir to current dir
743 # Dir is current module dir related to workspace
746 Dir
= Dir
[len(Workspace
) + 1:]
749 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
750 NewRelaPath
= RelaPath
753 # First check if File has Edk definition itself
754 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
755 File
= File
.replace('$(EFI_SOURCE)', EfiSource
)
756 File
= File
.replace('$(EDK_SOURCE)', EdkSource
)
757 NewFile
= AllFiles
[os
.path
.normpath(File
)]
759 NewRelaPath
= os
.path
.dirname(NewFile
)
760 File
= os
.path
.basename(NewFile
)
761 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
764 # Second check the path with override value
765 if OverrideDir
!= '' and OverrideDir
!= None:
766 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
768 #NewRelaPath = os.path.dirname(NewFile)
769 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
772 # Last check the path with normal definitions
773 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
780 return NewRelaPath
, RelaPath
, File
783 def GetRelPath(Path1
, Path2
):
784 FileName
= os
.path
.basename(Path2
)
785 L1
= os
.path
.normpath(Path1
).split(os
.path
.normpath('/'))
786 L2
= os
.path
.normpath(Path2
).split(os
.path
.normpath('/'))
787 for Index
in range(0, len(L1
)):
788 if L1
[Index
] != L2
[Index
]:
789 FileName
= '../' * (len(L1
) - Index
)
790 for Index2
in range(Index
, len(L2
)):
791 FileName
= os
.path
.join(FileName
, L2
[Index2
])
793 return os
.path
.normpath(FileName
)
796 ## Get GUID value from given packages
798 # @param CName The CName of the GUID
799 # @param PackageList List of packages looking-up in
800 # @param Inffile The driver file
802 # @retval GuidValue if the CName is found in any given package
803 # @retval None if the CName is not found in all given packages
805 def GuidValue(CName
, PackageList
, Inffile
= None):
806 for P
in PackageList
:
807 GuidKeys
= P
.Guids
.keys()
808 if Inffile
and P
._PrivateGuids
:
809 if not Inffile
.startswith(P
.MetaFile
.Dir
):
810 GuidKeys
= (dict.fromkeys(x
for x
in P
.Guids
if x
not in P
._PrivateGuids
)).keys()
811 if CName
in GuidKeys
:
812 return P
.Guids
[CName
]
815 ## Get Protocol value from given packages
817 # @param CName The CName of the GUID
818 # @param PackageList List of packages looking-up in
819 # @param Inffile The driver file
821 # @retval GuidValue if the CName is found in any given package
822 # @retval None if the CName is not found in all given packages
824 def ProtocolValue(CName
, PackageList
, Inffile
= None):
825 for P
in PackageList
:
826 ProtocolKeys
= P
.Protocols
.keys()
827 if Inffile
and P
._PrivateProtocols
:
828 if not Inffile
.startswith(P
.MetaFile
.Dir
):
829 ProtocolKeys
= (dict.fromkeys(x
for x
in P
.Protocols
if x
not in P
._PrivateProtocols
)).keys()
830 if CName
in ProtocolKeys
:
831 return P
.Protocols
[CName
]
834 ## Get PPI value from given packages
836 # @param CName The CName of the GUID
837 # @param PackageList List of packages looking-up in
838 # @param Inffile The driver file
840 # @retval GuidValue if the CName is found in any given package
841 # @retval None if the CName is not found in all given packages
843 def PpiValue(CName
, PackageList
, Inffile
= None):
844 for P
in PackageList
:
845 PpiKeys
= P
.Ppis
.keys()
846 if Inffile
and P
._PrivatePpis
:
847 if not Inffile
.startswith(P
.MetaFile
.Dir
):
848 PpiKeys
= (dict.fromkeys(x
for x
in P
.Ppis
if x
not in P
._PrivatePpis
)).keys()
853 ## A string template class
855 # This class implements a template for string replacement. A string template
856 # looks like following
858 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
860 # The string between ${BEGIN} and ${END} will be repeated as many times as the
861 # length of "placeholder_name", which is a list passed through a dict. The
862 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
863 # be not used and, in this case, the "placeholder_name" must not a list and it
864 # will just be replaced once.
866 class TemplateString(object):
867 _REPEAT_START_FLAG
= "BEGIN"
868 _REPEAT_END_FLAG
= "END"
870 class Section(object):
871 _LIST_TYPES
= [type([]), type(set()), type((0,))]
873 def __init__(self
, TemplateSection
, PlaceHolderList
):
874 self
._Template
= TemplateSection
875 self
._PlaceHolderList
= []
877 # Split the section into sub-sections according to the position of placeholders
879 self
._SubSectionList
= []
882 # The placeholders passed in must be in the format of
884 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
886 for PlaceHolder
, Start
, End
in PlaceHolderList
:
887 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
888 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
889 self
._PlaceHolderList
.append(PlaceHolder
)
890 SubSectionStart
= End
891 if SubSectionStart
< len(TemplateSection
):
892 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
894 self
._SubSectionList
= [TemplateSection
]
897 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
899 def Instantiate(self
, PlaceHolderValues
):
901 RepeatPlaceHolders
= {}
902 NonRepeatPlaceHolders
= {}
904 for PlaceHolder
in self
._PlaceHolderList
:
905 if PlaceHolder
not in PlaceHolderValues
:
907 Value
= PlaceHolderValues
[PlaceHolder
]
908 if type(Value
) in self
._LIST
_TYPES
:
910 RepeatTime
= len(Value
)
911 elif RepeatTime
!= len(Value
):
915 "${%s} has different repeat time from others!" % PlaceHolder
,
916 ExtraData
=str(self
._Template
)
918 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
920 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
922 if NonRepeatPlaceHolders
:
924 for S
in self
._SubSectionList
:
925 if S
not in NonRepeatPlaceHolders
:
928 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
930 StringList
= self
._SubSectionList
932 if RepeatPlaceHolders
:
934 for Index
in range(RepeatTime
):
936 if S
not in RepeatPlaceHolders
:
937 TempStringList
.append(S
)
939 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
940 StringList
= TempStringList
942 return "".join(StringList
)
945 def __init__(self
, Template
=None):
947 self
.IsBinary
= False
948 self
._Template
= Template
949 self
._TemplateSectionList
= self
._Parse
(Template
)
953 # @retval string The string replaced
958 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
960 # @retval list A list of TemplateString.Section objects
962 def _Parse(self
, Template
):
967 TemplateSectionList
= []
969 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
971 if MatchEnd
<= len(Template
):
972 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
973 TemplateSectionList
.append(TemplateSection
)
976 MatchString
= MatchObj
.group(1)
977 MatchStart
= MatchObj
.start()
978 MatchEnd
= MatchObj
.end()
980 if MatchString
== self
._REPEAT
_START
_FLAG
:
981 if MatchStart
> SectionStart
:
982 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
983 TemplateSectionList
.append(TemplateSection
)
984 SectionStart
= MatchEnd
986 elif MatchString
== self
._REPEAT
_END
_FLAG
:
987 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
988 TemplateSectionList
.append(TemplateSection
)
989 SectionStart
= MatchEnd
992 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
993 SearchFrom
= MatchEnd
994 return TemplateSectionList
996 ## Replace the string template with dictionary of placeholders and append it to previous one
998 # @param AppendString The string template to append
999 # @param Dictionary The placeholder dictionaries
1001 def Append(self
, AppendString
, Dictionary
=None):
1003 SectionList
= self
._Parse
(AppendString
)
1004 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
1006 self
.String
+= AppendString
1008 ## Replace the string template with dictionary of placeholders
1010 # @param Dictionary The placeholder dictionaries
1012 # @retval str The string replaced with placeholder values
1014 def Replace(self
, Dictionary
=None):
1015 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
1017 ## Progress indicator class
1019 # This class makes use of thread to print progress on console.
1022 # for avoiding deadloop
1024 _ProgressThread
= None
1025 _CheckInterval
= 0.25
1029 # @param OpenMessage The string printed before progress charaters
1030 # @param CloseMessage The string printed after progress charaters
1031 # @param ProgressChar The charater used to indicate the progress
1032 # @param Interval The interval in seconds between two progress charaters
1034 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
1035 self
.PromptMessage
= OpenMessage
1036 self
.CodaMessage
= CloseMessage
1037 self
.ProgressChar
= ProgressChar
1038 self
.Interval
= Interval
1039 if Progressor
._StopFlag
== None:
1040 Progressor
._StopFlag
= threading
.Event()
1042 ## Start to print progress charater
1044 # @param OpenMessage The string printed before progress charaters
1046 def Start(self
, OpenMessage
=None):
1047 if OpenMessage
!= None:
1048 self
.PromptMessage
= OpenMessage
1049 Progressor
._StopFlag
.clear()
1050 if Progressor
._ProgressThread
== None:
1051 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
1052 Progressor
._ProgressThread
.setDaemon(False)
1053 Progressor
._ProgressThread
.start()
1055 ## Stop printing progress charater
1057 # @param CloseMessage The string printed after progress charaters
1059 def Stop(self
, CloseMessage
=None):
1060 OriginalCodaMessage
= self
.CodaMessage
1061 if CloseMessage
!= None:
1062 self
.CodaMessage
= CloseMessage
1064 self
.CodaMessage
= OriginalCodaMessage
1066 ## Thread entry method
1067 def _ProgressThreadEntry(self
):
1068 sys
.stdout
.write(self
.PromptMessage
+ " ")
1071 while not Progressor
._StopFlag
.isSet():
1073 sys
.stdout
.write(self
.ProgressChar
)
1075 TimeUp
= self
.Interval
1076 time
.sleep(self
._CheckInterval
)
1077 TimeUp
-= self
._CheckInterval
1078 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
1081 ## Abort the progress display
1084 if Progressor
._StopFlag
!= None:
1085 Progressor
._StopFlag
.set()
1086 if Progressor
._ProgressThread
!= None:
1087 Progressor
._ProgressThread
.join()
1088 Progressor
._ProgressThread
= None
1090 ## A dict which can access its keys and/or values orderly
1092 # The class implements a new kind of dict which its keys or values can be
1093 # accessed in the order they are added into the dict. It guarantees the order
1094 # by making use of an internal list to keep a copy of keys.
1096 class sdict(IterableUserDict
):
1099 IterableUserDict
.__init
__(self
)
1103 def __setitem__(self
, key
, value
):
1104 if key
not in self
._key
_list
:
1105 self
._key
_list
.append(key
)
1106 IterableUserDict
.__setitem
__(self
, key
, value
)
1109 def __delitem__(self
, key
):
1110 self
._key
_list
.remove(key
)
1111 IterableUserDict
.__delitem
__(self
, key
)
1113 ## used in "for k in dict" loop to ensure the correct order
1115 return self
.iterkeys()
1119 return len(self
._key
_list
)
1121 ## "in" test support
1122 def __contains__(self
, key
):
1123 return key
in self
._key
_list
1126 def index(self
, key
):
1127 return self
._key
_list
.index(key
)
1130 def insert(self
, key
, newkey
, newvalue
, order
):
1131 index
= self
._key
_list
.index(key
)
1132 if order
== 'BEFORE':
1133 self
._key
_list
.insert(index
, newkey
)
1134 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1135 elif order
== 'AFTER':
1136 self
._key
_list
.insert(index
+ 1, newkey
)
1137 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1140 def append(self
, sdict
):
1142 if key
not in self
._key
_list
:
1143 self
._key
_list
.append(key
)
1144 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
1146 def has_key(self
, key
):
1147 return key
in self
._key
_list
1152 IterableUserDict
.clear(self
)
1154 ## Return a copy of keys
1157 for key
in self
._key
_list
:
1161 ## Return a copy of values
1164 for key
in self
._key
_list
:
1165 values
.append(self
[key
])
1168 ## Return a copy of (key, value) list
1171 for key
in self
._key
_list
:
1172 items
.append((key
, self
[key
]))
1175 ## Iteration support
1176 def iteritems(self
):
1177 return iter(self
.items())
1179 ## Keys interation support
1181 return iter(self
.keys())
1183 ## Values interation support
1184 def itervalues(self
):
1185 return iter(self
.values())
1187 ## Return value related to a key, and remove the (key, value) from the dict
1188 def pop(self
, key
, *dv
):
1190 if key
in self
._key
_list
:
1192 self
.__delitem
__(key
)
1197 ## Return (key, value) pair, and remove the (key, value) from the dict
1199 key
= self
._key
_list
[-1]
1201 self
.__delitem
__(key
)
1204 def update(self
, dict=None, **kwargs
):
1206 for k
, v
in dict.items():
1209 for k
, v
in kwargs
.items():
1212 ## Dictionary with restricted keys
1216 def __init__(self
, KeyList
):
1218 dict.__setitem
__(self
, Key
, "")
1221 def __setitem__(self
, key
, value
):
1223 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1224 ExtraData
=", ".join(dict.keys(self
)))
1225 dict.__setitem
__(self
, key
, value
)
1228 def __getitem__(self
, key
):
1231 return dict.__getitem
__(self
, key
)
1234 def __delitem__(self
, key
):
1235 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1240 self
.__setitem
__(Key
, "")
1242 ## Return value related to a key, and remove the (key, value) from the dict
1243 def pop(self
, key
, *dv
):
1244 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1246 ## Return (key, value) pair, and remove the (key, value) from the dict
1248 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1250 ## Dictionary using prioritized list as key
1253 _ListType
= type([])
1254 _TupleType
= type(())
1255 _Wildcard
= 'COMMON'
1256 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1258 def __init__(self
, _Single_
=False, _Level_
=2):
1259 self
._Level
_ = _Level_
1261 self
._Single
_ = _Single_
1264 def __getitem__(self
, key
):
1267 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1271 elif self
._Level
_ > 1:
1272 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1275 if self
._Level
_ > 1:
1276 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1278 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1279 FirstKey
= self
._Wildcard
1282 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1284 return self
._GetAllValues
(FirstKey
, RestKeys
)
1286 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1288 #print "%s-%s" % (FirstKey, self._Level_) ,
1289 if self
._Level
_ > 1:
1290 if FirstKey
== self
._Wildcard
:
1291 if FirstKey
in self
.data
:
1292 Value
= self
.data
[FirstKey
][RestKeys
]
1294 for Key
in self
.data
:
1295 Value
= self
.data
[Key
][RestKeys
]
1296 if Value
!= None: break
1298 if FirstKey
in self
.data
:
1299 Value
= self
.data
[FirstKey
][RestKeys
]
1300 if Value
== None and self
._Wildcard
in self
.data
:
1302 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1304 if FirstKey
== self
._Wildcard
:
1305 if FirstKey
in self
.data
:
1306 Value
= self
.data
[FirstKey
]
1308 for Key
in self
.data
:
1309 Value
= self
.data
[Key
]
1310 if Value
!= None: break
1312 if FirstKey
in self
.data
:
1313 Value
= self
.data
[FirstKey
]
1314 elif self
._Wildcard
in self
.data
:
1315 Value
= self
.data
[self
._Wildcard
]
1318 def _GetAllValues(self
, FirstKey
, RestKeys
):
1320 if self
._Level
_ > 1:
1321 if FirstKey
== self
._Wildcard
:
1322 for Key
in self
.data
:
1323 Value
+= self
.data
[Key
][RestKeys
]
1325 if FirstKey
in self
.data
:
1326 Value
+= self
.data
[FirstKey
][RestKeys
]
1327 if self
._Wildcard
in self
.data
:
1328 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1330 if FirstKey
== self
._Wildcard
:
1331 for Key
in self
.data
:
1332 Value
.append(self
.data
[Key
])
1334 if FirstKey
in self
.data
:
1335 Value
.append(self
.data
[FirstKey
])
1336 if self
._Wildcard
in self
.data
:
1337 Value
.append(self
.data
[self
._Wildcard
])
1341 def __setitem__(self
, key
, value
):
1344 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1349 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1352 if self
._Level
_ > 1:
1353 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1355 if FirstKey
in self
._ValidWildcardList
:
1356 FirstKey
= self
._Wildcard
1358 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1359 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1361 if self
._Level
_ > 1:
1362 self
.data
[FirstKey
][RestKeys
] = value
1364 self
.data
[FirstKey
] = value
1366 def SetGreedyMode(self
):
1367 self
._Single
_ = False
1368 if self
._Level
_ > 1:
1369 for Key
in self
.data
:
1370 self
.data
[Key
].SetGreedyMode()
1372 def SetSingleMode(self
):
1373 self
._Single
_ = True
1374 if self
._Level
_ > 1:
1375 for Key
in self
.data
:
1376 self
.data
[Key
].SetSingleMode()
1378 def GetKeys(self
, KeyIndex
=0):
1379 assert KeyIndex
>= 0
1381 return set(self
.data
.keys())
1384 for Key
in self
.data
:
1385 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1388 ## Boolean chain list
1390 class Blist(UserList
):
1391 def __init__(self
, initlist
=None):
1392 UserList
.__init
__(self
, initlist
)
1393 def __setitem__(self
, i
, item
):
1394 if item
not in [True, False]:
1400 def _GetResult(self
):
1402 for item
in self
.data
:
1405 Result
= property(_GetResult
)
1407 def ParseConsoleLog(Filename
):
1408 Opr
= open(os
.path
.normpath(Filename
), 'r')
1409 Opw
= open(os
.path
.normpath(Filename
+ '.New'), 'w+')
1410 for Line
in Opr
.readlines():
1411 if Line
.find('.efi') > -1:
1412 Line
= Line
[Line
.rfind(' ') : Line
.rfind('.efi')].strip()
1413 Opw
.write('%s\n' % Line
)
1418 def AnalyzePcdExpression(Setting
):
1419 Setting
= Setting
.strip()
1420 # There might be escaped quote in a string: \", \\\"
1421 Data
= Setting
.replace('\\\\', '//').replace('\\\"', '\\\'')
1422 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1429 elif ch
== '(' and not InStr
:
1431 elif ch
== ')' and not InStr
:
1434 if (Pair
> 0 or InStr
) and ch
== TAB_VALUE_SPLIT
:
1441 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1443 FieldList
.append(Setting
[StartPos
:].strip())
1445 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1452 # Analyze DSC PCD value, since there is no data type info in DSC
1453 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1454 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1455 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1456 # 3. Dynamic default:
1457 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1458 # TokenSpace.PcdCName|PcdValue
1460 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1461 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1463 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1464 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1465 # there might have "|" operator, also in string value.
1467 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1468 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1469 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1471 # ValueList: A List contain fields described above
1472 # IsValid: True if conforming EBNF, otherwise False
1473 # Index: The index where PcdValue is in ValueList
1475 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1476 FieldList
= AnalyzePcdExpression(Setting
)
1479 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1480 Value
= FieldList
[0]
1482 if len(FieldList
) > 1:
1484 # Fix the PCD type when no DataType input
1489 if len(FieldList
) > 2:
1491 if DataType
== 'VOID*':
1492 IsValid
= (len(FieldList
) <= 3)
1494 IsValid
= (len(FieldList
) <= 1)
1495 return [Value
, '', Size
], IsValid
, 0
1496 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1497 Value
= FieldList
[0]
1499 if len(FieldList
) > 1:
1503 if len(FieldList
) > 2:
1507 if Value
.startswith("L"):
1508 Size
= str((len(Value
)- 3 + 1) * 2)
1509 elif Value
.startswith("{"):
1510 Size
= str(len(Value
.split(",")))
1512 Size
= str(len(Value
) -2 + 1 )
1513 if DataType
== 'VOID*':
1514 IsValid
= (len(FieldList
) <= 3)
1516 IsValid
= (len(FieldList
) <= 1)
1517 return [Value
, Type
, Size
], IsValid
, 0
1518 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1519 VpdOffset
= FieldList
[0]
1521 if not DataType
== 'VOID*':
1522 if len(FieldList
) > 1:
1523 Value
= FieldList
[1]
1525 if len(FieldList
) > 1:
1527 if len(FieldList
) > 2:
1528 Value
= FieldList
[2]
1529 if DataType
== 'VOID*':
1530 IsValid
= (len(FieldList
) <= 3)
1532 IsValid
= (len(FieldList
) <= 2)
1533 return [VpdOffset
, Size
, Value
], IsValid
, 2
1534 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1535 HiiString
= FieldList
[0]
1536 Guid
= Offset
= Value
= Attribute
= ''
1537 if len(FieldList
) > 1:
1539 if len(FieldList
) > 2:
1540 Offset
= FieldList
[2]
1541 if len(FieldList
) > 3:
1542 Value
= FieldList
[3]
1543 if len(FieldList
) > 4:
1544 Attribute
= FieldList
[4]
1545 IsValid
= (3 <= len(FieldList
) <= 5)
1546 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1551 # Analyze the pcd Value, Datum type and TokenNumber.
1552 # Used to avoid split issue while the value string contain "|" character
1554 # @param[in] Setting: A String contain value/datum type/token number information;
1556 # @retval ValueList: A List contain value, datum type and toke number.
1558 def AnalyzePcdData(Setting
):
1559 ValueList
= ['', '', '']
1561 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1562 PtrValue
= ValueRe
.findall(Setting
)
1564 ValueUpdateFlag
= False
1566 if len(PtrValue
) >= 1:
1567 Setting
= re
.sub(ValueRe
, '', Setting
)
1568 ValueUpdateFlag
= True
1570 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1571 ValueList
[0:len(TokenList
)] = TokenList
1574 ValueList
[0] = PtrValue
[0]
1578 ## AnalyzeHiiPcdData
1580 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1581 # Used to avoid split issue while the value string contain "|" character
1583 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1585 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1587 def AnalyzeHiiPcdData(Setting
):
1588 ValueList
= ['', '', '', '']
1590 TokenList
= GetSplitValueList(Setting
)
1591 ValueList
[0:len(TokenList
)] = TokenList
1595 ## AnalyzeVpdPcdData
1597 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1598 # Used to avoid split issue while the value string contain "|" character
1600 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1602 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1604 def AnalyzeVpdPcdData(Setting
):
1605 ValueList
= ['', '', '']
1607 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1608 PtrValue
= ValueRe
.findall(Setting
)
1610 ValueUpdateFlag
= False
1612 if len(PtrValue
) >= 1:
1613 Setting
= re
.sub(ValueRe
, '', Setting
)
1614 ValueUpdateFlag
= True
1616 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1617 ValueList
[0:len(TokenList
)] = TokenList
1620 ValueList
[2] = PtrValue
[0]
1624 ## check format of PCD value against its the datum type
1626 # For PCD value setting
1628 def CheckPcdDatum(Type
, Value
):
1630 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1631 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1632 or (Value
.startswith('{') and Value
.endswith('}'))
1634 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1635 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1636 elif ValueRe
.match(Value
):
1637 # Check the chars in UnicodeString or CString is printable
1638 if Value
.startswith("L"):
1642 Printset
= set(string
.printable
)
1643 Printset
.remove(TAB_PRINTCHAR_VT
)
1644 Printset
.add(TAB_PRINTCHAR_BS
)
1645 Printset
.add(TAB_PRINTCHAR_NUL
)
1646 if not set(Value
).issubset(Printset
):
1647 PrintList
= list(Printset
)
1649 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1650 elif Type
== 'BOOLEAN':
1651 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1652 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1653 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1654 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1656 Value
= long(Value
, 0)
1658 return False, "Invalid value [%s] of type [%s];"\
1659 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1661 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type
)
1665 ## Split command line option string to list
1667 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1668 # in non-windows platform to launch command
1670 def SplitOption(OptionString
):
1675 for Index
in range(0, len(OptionString
)):
1676 CurrentChar
= OptionString
[Index
]
1677 if CurrentChar
in ['"', "'"]:
1678 if QuotationMark
== CurrentChar
:
1680 elif QuotationMark
== "":
1681 QuotationMark
= CurrentChar
1686 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1687 if Index
> OptionStart
:
1688 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1690 LastChar
= CurrentChar
1691 OptionList
.append(OptionString
[OptionStart
:])
1694 def CommonPath(PathList
):
1695 P1
= min(PathList
).split(os
.path
.sep
)
1696 P2
= max(PathList
).split(os
.path
.sep
)
1697 for Index
in xrange(min(len(P1
), len(P2
))):
1698 if P1
[Index
] != P2
[Index
]:
1699 return os
.path
.sep
.join(P1
[:Index
])
1700 return os
.path
.sep
.join(P1
)
1703 # Convert string to C format array
1705 def ConvertStringToByteArray(Value
):
1706 Value
= Value
.strip()
1710 if not Value
.endswith('}'):
1712 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1713 ValFields
= Value
.split(',')
1715 for Index
in range(len(ValFields
)):
1716 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1719 Value
= '{' + ','.join(ValFields
) + '}'
1723 if Value
.startswith('L"'):
1724 if not Value
.endswith('"'):
1728 elif not Value
.startswith('"') or not Value
.endswith('"'):
1731 Value
= eval(Value
) # translate escape character
1733 for Index
in range(0,len(Value
)):
1735 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1737 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1738 Value
= NewValue
+ '0}'
1741 class PathClass(object):
1742 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1743 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1745 self
.File
= str(File
)
1746 if os
.path
.isabs(self
.File
):
1750 self
.Root
= str(Root
)
1751 self
.AlterRoot
= str(AlterRoot
)
1753 # Remove any '.' and '..' in path
1755 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1756 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1757 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1758 # eliminate the side-effect of 'C:'
1759 if self
.Root
[-1] == ':':
1760 self
.Root
+= os
.path
.sep
1761 # file path should not start with path separator
1762 if self
.Root
[-1] == os
.path
.sep
:
1763 self
.File
= self
.Path
[len(self
.Root
):]
1765 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1767 self
.Path
= os
.path
.normpath(self
.File
)
1769 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1770 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1774 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1776 self
.Dir
= self
.Root
1778 self
.Dir
= self
.SubDir
1783 self
.Type
= self
.Ext
.lower()
1785 self
.IsBinary
= IsBinary
1786 self
.Target
= Target
1787 self
.TagName
= TagName
1788 self
.ToolCode
= ToolCode
1789 self
.ToolChainFamily
= ToolChainFamily
1793 ## Convert the object of this class to a string
1795 # Convert member Path of the class to a string
1797 # @retval string Formatted String
1802 ## Override __eq__ function
1804 # Check whether PathClass are the same
1806 # @retval False The two PathClass are different
1807 # @retval True The two PathClass are the same
1809 def __eq__(self
, Other
):
1810 if type(Other
) == type(self
):
1811 return self
.Path
== Other
.Path
1813 return self
.Path
== str(Other
)
1815 ## Override __cmp__ function
1817 # Customize the comparsion operation of two PathClass
1819 # @retval 0 The two PathClass are different
1820 # @retval -1 The first PathClass is less than the second PathClass
1821 # @retval 1 The first PathClass is Bigger than the second PathClass
1822 def __cmp__(self
, Other
):
1823 if type(Other
) == type(self
):
1824 OtherKey
= Other
.Path
1826 OtherKey
= str(Other
)
1829 if SelfKey
== OtherKey
:
1831 elif SelfKey
> OtherKey
:
1836 ## Override __hash__ function
1838 # Use Path as key in hash table
1840 # @retval string Key for hash table
1843 return hash(self
.Path
)
1845 def _GetFileKey(self
):
1846 if self
._Key
== None:
1847 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1850 def _GetTimeStamp(self
):
1851 return os
.stat(self
.Path
)[8]
1853 def Validate(self
, Type
='', CaseSensitive
=True):
1854 if GlobalData
.gCaseInsensitive
:
1855 CaseSensitive
= False
1856 if Type
and Type
.lower() != self
.Type
:
1857 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1859 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1860 if not RealRoot
and not RealFile
:
1861 RealFile
= self
.File
1863 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1865 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1866 if len (mws
.getPkgPath()) == 0:
1867 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1869 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1873 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1874 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1875 ErrorCode
= FILE_CASE_MISMATCH
1876 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1878 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1879 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1881 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1884 self
.File
= RealFile
1885 self
.Root
= RealRoot
1886 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1887 return ErrorCode
, ErrorInfo
1889 Key
= property(_GetFileKey
)
1890 TimeStamp
= property(_GetTimeStamp
)
1892 ## Parse PE image to get the required PE informaion.
1894 class PeImageClass():
1897 # @param File FilePath of PeImage
1899 def __init__(self
, PeFile
):
1900 self
.FileName
= PeFile
1901 self
.IsValid
= False
1904 self
.SectionAlignment
= 0
1905 self
.SectionHeaderList
= []
1908 PeObject
= open(PeFile
, 'rb')
1910 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1913 ByteArray
= array
.array('B')
1914 ByteArray
.fromfile(PeObject
, 0x3E)
1915 ByteList
= ByteArray
.tolist()
1916 # DOS signature should be 'MZ'
1917 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1918 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1921 # Read 4 byte PE Signature
1922 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1923 PeObject
.seek(PeOffset
)
1924 ByteArray
= array
.array('B')
1925 ByteArray
.fromfile(PeObject
, 4)
1926 # PE signature should be 'PE\0\0'
1927 if ByteArray
.tostring() != 'PE\0\0':
1928 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1931 # Read PE file header
1932 ByteArray
= array
.array('B')
1933 ByteArray
.fromfile(PeObject
, 0x14)
1934 ByteList
= ByteArray
.tolist()
1935 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1937 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1940 # Read PE optional header
1941 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1942 ByteArray
= array
.array('B')
1943 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1944 ByteList
= ByteArray
.tolist()
1945 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1946 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1947 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1949 # Read each Section Header
1950 for Index
in range(SecNumber
):
1951 ByteArray
= array
.array('B')
1952 ByteArray
.fromfile(PeObject
, 0x28)
1953 ByteList
= ByteArray
.tolist()
1954 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1955 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1956 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1957 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1958 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1962 def _ByteListToStr(self
, ByteList
):
1964 for index
in range(len(ByteList
)):
1965 if ByteList
[index
] == 0:
1967 String
+= chr(ByteList
[index
])
1970 def _ByteListToInt(self
, ByteList
):
1972 for index
in range(len(ByteList
) - 1, -1, -1):
1973 Value
= (Value
<< 8) |
int(ByteList
[index
])
1983 def __init__(self
,SkuIdentifier
='', SkuIds
={}):
1985 self
.AvailableSkuIds
= sdict()
1987 self
.SkuIdNumberSet
= []
1988 if SkuIdentifier
== '' or SkuIdentifier
is None:
1989 self
.SkuIdSet
= ['DEFAULT']
1990 self
.SkuIdNumberSet
= ['0U']
1991 elif SkuIdentifier
== 'ALL':
1992 self
.SkuIdSet
= SkuIds
.keys()
1993 self
.SkuIdNumberSet
= [num
.strip() + 'U' for num
in SkuIds
.values()]
1995 r
= SkuIdentifier
.split('|')
1996 self
.SkuIdSet
=[r
[k
].strip() for k
in range(len(r
))]
1999 self
.SkuIdNumberSet
= [SkuIds
[k
].strip() + 'U' for k
in self
.SkuIdSet
]
2001 EdkLogger
.error("build", PARAMETER_INVALID
,
2002 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
2003 % (k
, " ".join(SkuIds
.keys())))
2004 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
and SkuIdentifier
!= 'ALL':
2005 self
.SkuIdSet
.remove('DEFAULT')
2006 self
.SkuIdNumberSet
.remove('0U')
2007 for each
in self
.SkuIdSet
:
2009 self
.AvailableSkuIds
[each
] = SkuIds
[each
]
2011 EdkLogger
.error("build", PARAMETER_INVALID
,
2012 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
2013 % (each
, " ".join(SkuIds
.keys())))
2015 def __SkuUsageType(self
):
2017 if len(self
.SkuIdSet
) == 1:
2018 if self
.SkuIdSet
[0] == 'DEFAULT':
2019 return SkuClass
.DEFAULT
2021 return SkuClass
.SINGLE
2023 return SkuClass
.MULTIPLE
2025 def __GetAvailableSkuIds(self
):
2026 return self
.AvailableSkuIds
2028 def __GetSystemSkuID(self
):
2029 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2030 return self
.SkuIdSet
[0]
2033 def __GetAvailableSkuIdNumber(self
):
2034 return self
.SkuIdNumberSet
2035 SystemSkuId
= property(__GetSystemSkuID
)
2036 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2037 SkuUsageType
= property(__SkuUsageType
)
2038 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2041 # Pack a registry format GUID
2043 def PackRegistryFormatGuid(Guid
):
2044 Guid
= Guid
.split('-')
2045 return pack('=LHHBBBBBBBB',
2049 int(Guid
[3][-4:-2], 16),
2050 int(Guid
[3][-2:], 16),
2051 int(Guid
[4][-12:-10], 16),
2052 int(Guid
[4][-10:-8], 16),
2053 int(Guid
[4][-8:-6], 16),
2054 int(Guid
[4][-6:-4], 16),
2055 int(Guid
[4][-4:-2], 16),
2056 int(Guid
[4][-2:], 16)
2061 # This acts like the main() function for the script, unless it is 'import'ed into another
2064 if __name__
== '__main__':