2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2015, 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 UserDict
import IterableUserDict
28 from UserList
import UserList
30 from Common
import EdkLogger
as EdkLogger
31 from Common
import GlobalData
as GlobalData
32 from DataType
import *
33 from BuildToolError
import *
34 from CommonDataClass
.DataClass
import *
35 from Parsing
import GetSplitValueList
36 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
38 ## Regular expression used to find out place holders in string template
39 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE|re
.UNICODE
)
41 ## Dictionary used to store file time stamp for quick re-access
42 gFileTimeStampCache
= {} # {file path : file time stamp}
44 ## Dictionary used to store dependencies of files
45 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
47 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
48 """ Parse map file to get variable offset in current EFI file
49 @param mapfilepath Map file absolution path
50 @param efifilepath: EFI binary file full path
51 @param varnames iteratable container whose elements are variable names to be searched
53 @return List whos elements are tuple with variable name and raw offset
57 f
= open(mapfilepath
, 'r')
63 if len(lines
) == 0: return None
64 firstline
= lines
[0].strip()
65 if (firstline
.startswith("Archive member included ") and
66 firstline
.endswith(" file (symbol)")):
67 return _parseForGCC(lines
, efifilepath
, varnames
)
68 return _parseGeneral(lines
, efifilepath
, varnames
)
70 def _parseForGCC(lines
, efifilepath
, varnames
):
71 """ Parse map file generated by GCC linker """
77 # status machine transection
78 if status
== 0 and line
== "Memory Configuration":
81 elif status
== 1 and line
== 'Linker script and memory map':
84 elif status
==2 and line
== 'START GROUP':
90 m
= re
.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line
)
92 sections
.append(m
.groups(0))
93 for varname
in varnames
:
94 m
= re
.match("^([\da-fA-Fx]+) +[_]*(%s)$" % varname
, line
)
96 varoffset
.append((varname
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
100 # get section information from efi file
101 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
102 if efisecs
== None or len(efisecs
) == 0:
106 for efisec
in efisecs
:
107 for section
in sections
:
108 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
109 redirection
= int(section
[1], 16) - efisec
[1]
112 for var
in varoffset
:
113 for efisec
in efisecs
:
114 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
115 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
118 def _parseGeneral(lines
, efifilepath
, varnames
):
119 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
120 secs
= [] # key = section name
122 secRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
123 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
127 if re
.match("^Start[' ']+Length[' ']+Name[' ']+Class", line
):
130 if re
.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line
):
133 if re
.match("^entry point at", line
):
136 if status
== 1 and len(line
) != 0:
137 m
= secRe
.match(line
)
138 assert m
!= None, "Fail to parse the section in map file , line is %s" % line
139 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
140 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
141 if status
== 2 and len(line
) != 0:
142 for varname
in varnames
:
143 m
= symRe
.match(line
)
144 assert m
!= None, "Fail to parse the symbol in map file, line is %s" % line
145 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
146 sec_no
= int(sec_no
, 16)
147 sym_offset
= int(sym_offset
, 16)
148 vir_addr
= int(vir_addr
, 16)
149 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
151 # fond a binary pcd entry in map file
153 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
154 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
156 if not varoffset
: return []
158 # get section information from efi file
159 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
160 if efisecs
== None or len(efisecs
) == 0:
164 for var
in varoffset
:
166 for efisec
in efisecs
:
168 if var
[1].strip() == efisec
[0].strip():
169 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
170 elif var
[4] == index
:
171 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
175 ## Routine to process duplicated INF
177 # This function is called by following two cases:
180 # Pkg/module/module.inf
181 # Pkg/module/module.inf {
183 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
186 # INF Pkg/module/module.inf
187 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
189 # This function copies Pkg/module/module.inf to
190 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
192 # @param Path Original PathClass object
193 # @param BaseName New file base name
195 # @retval return the new PathClass object
197 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
198 Filename
= os
.path
.split(Path
.File
)[1]
200 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
202 Filename
= BaseName
+ Path
.BaseName
205 # If -N is specified on command line, cache is disabled
206 # The directory has to be created
208 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
209 if not os
.path
.exists(DbDir
):
212 # A temporary INF is copied to database path which must have write permission
213 # The temporary will be removed at the end of build
214 # In case of name conflict, the file name is
215 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
217 TempFullPath
= os
.path
.join(DbDir
,
219 RtPath
= PathClass(Path
.File
, Workspace
)
221 # Modify the full path to temporary path, keep other unchanged
223 # To build same module more than once, the module path with FILE_GUID overridden has
224 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
225 # in DSC which is used as relative path by C files and other files in INF.
226 # A trick was used: all module paths are PathClass instances, after the initialization
227 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
229 # The reason for creating a temporary INF is:
230 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
231 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
232 # A different key for the same module is needed to create different output directory,
233 # retrieve overridden PCDs, library instances.
235 # The BaseName is the FILE_GUID which is also the output directory name.
238 RtPath
.Path
= TempFullPath
239 RtPath
.BaseName
= BaseName
241 # If file exists, compare contents
243 if os
.path
.exists(TempFullPath
):
244 with
open(str(Path
), 'rb') as f1
: Src
= f1
.read()
245 with
open(TempFullPath
, 'rb') as f2
: Dst
= f2
.read()
248 GlobalData
.gTempInfs
.append(TempFullPath
)
249 shutil
.copy2(str(Path
), TempFullPath
)
252 ## Remove temporary created INFs whose paths were saved in gTempInfs
254 def ClearDuplicatedInf():
255 for File
in GlobalData
.gTempInfs
:
256 if os
.path
.exists(File
):
259 ## callback routine for processing variable option
261 # This function can be used to process variable number of option values. The
262 # typical usage of it is specify architecure list on command line.
263 # (e.g. <tool> -a IA32 X64 IPF)
265 # @param Option Standard callback function parameter
266 # @param OptionString Standard callback function parameter
267 # @param Value Standard callback function parameter
268 # @param Parser Standard callback function parameter
272 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
275 RawArgs
= Parser
.rargs
278 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
279 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
283 setattr(Parser
.values
, Option
.dest
, Value
)
285 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
287 # @param Guid The GUID string
289 # @retval string The GUID string in C structure style
291 def GuidStringToGuidStructureString(Guid
):
292 GuidList
= Guid
.split('-')
294 for Index
in range(0,3,1):
295 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
296 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
297 for Index
in range(0,12,2):
298 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+2]
302 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
304 # @param GuidValue The GUID value in byte array
306 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
308 def GuidStructureByteArrayToGuidString(GuidValue
):
309 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
310 guidValueList
= guidValueString
.split(",")
311 if len(guidValueList
) != 16:
313 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
315 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
316 int(guidValueList
[3], 16),
317 int(guidValueList
[2], 16),
318 int(guidValueList
[1], 16),
319 int(guidValueList
[0], 16),
320 int(guidValueList
[5], 16),
321 int(guidValueList
[4], 16),
322 int(guidValueList
[7], 16),
323 int(guidValueList
[6], 16),
324 int(guidValueList
[8], 16),
325 int(guidValueList
[9], 16),
326 int(guidValueList
[10], 16),
327 int(guidValueList
[11], 16),
328 int(guidValueList
[12], 16),
329 int(guidValueList
[13], 16),
330 int(guidValueList
[14], 16),
331 int(guidValueList
[15], 16)
336 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
338 # @param GuidValue The GUID value in C structure format
340 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
342 def GuidStructureStringToGuidString(GuidValue
):
343 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
344 guidValueList
= guidValueString
.split(",")
345 if len(guidValueList
) != 11:
347 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
349 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
350 int(guidValueList
[0], 16),
351 int(guidValueList
[1], 16),
352 int(guidValueList
[2], 16),
353 int(guidValueList
[3], 16),
354 int(guidValueList
[4], 16),
355 int(guidValueList
[5], 16),
356 int(guidValueList
[6], 16),
357 int(guidValueList
[7], 16),
358 int(guidValueList
[8], 16),
359 int(guidValueList
[9], 16),
360 int(guidValueList
[10], 16)
365 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
367 # @param GuidValue The GUID value in C structure format
369 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
371 def GuidStructureStringToGuidValueName(GuidValue
):
372 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
373 guidValueList
= guidValueString
.split(",")
374 if len(guidValueList
) != 11:
375 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
376 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
377 int(guidValueList
[0], 16),
378 int(guidValueList
[1], 16),
379 int(guidValueList
[2], 16),
380 int(guidValueList
[3], 16),
381 int(guidValueList
[4], 16),
382 int(guidValueList
[5], 16),
383 int(guidValueList
[6], 16),
384 int(guidValueList
[7], 16),
385 int(guidValueList
[8], 16),
386 int(guidValueList
[9], 16),
387 int(guidValueList
[10], 16)
390 ## Create directories
392 # @param Directory The directory name
394 def CreateDirectory(Directory
):
395 if Directory
== None or Directory
.strip() == "":
398 if not os
.access(Directory
, os
.F_OK
):
399 os
.makedirs(Directory
)
404 ## Remove directories, including files and sub-directories in it
406 # @param Directory The directory name
408 def RemoveDirectory(Directory
, Recursively
=False):
409 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
412 CurrentDirectory
= os
.getcwd()
414 for File
in os
.listdir("."):
415 if os
.path
.isdir(File
):
416 RemoveDirectory(File
, Recursively
)
419 os
.chdir(CurrentDirectory
)
422 ## Check if given file is changed or not
424 # This method is used to check if a file is changed or not between two build
425 # actions. It makes use a cache to store files timestamp.
427 # @param File The path of file
429 # @retval True If the given file is changed, doesn't exist, or can't be
430 # found in timestamp cache
431 # @retval False If the given file is changed
434 if not os
.path
.exists(File
):
437 FileState
= os
.stat(File
)
438 TimeStamp
= FileState
[-2]
440 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
444 gFileTimeStampCache
[File
] = TimeStamp
448 ## Store content in file
450 # This method is used to save file only when its content is changed. This is
451 # quite useful for "make" system to decide what will be re-built and what won't.
453 # @param File The path of file
454 # @param Content The new content of the file
455 # @param IsBinaryFile The flag indicating if the file is binary file or not
457 # @retval True If the file content is changed and the file is renewed
458 # @retval False If the file content is the same
460 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
462 Content
= Content
.replace("\n", os
.linesep
)
464 if os
.path
.exists(File
):
466 if Content
== open(File
, "rb").read():
469 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
471 DirName
= os
.path
.dirname(File
)
472 if not CreateDirectory(DirName
):
473 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
476 DirName
= os
.getcwd()
477 if not os
.access(DirName
, os
.W_OK
):
478 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
481 if GlobalData
.gIsWindows
:
483 from PyUtility
import SaveFileToDisk
484 if not SaveFileToDisk(File
, Content
):
485 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
487 Fd
= open(File
, "wb")
491 Fd
= open(File
, "wb")
495 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s'%X)
499 ## Make a Python object persistent on file system
501 # @param Data The object to be stored in file
502 # @param File The path of file to store the object
504 def DataDump(Data
, File
):
507 Fd
= open(File
, 'wb')
508 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
510 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
515 ## Restore a Python object from a file
517 # @param File The path of file stored the object
519 # @retval object A python object
520 # @retval None If failure in file operation
522 def DataRestore(File
):
526 Fd
= open(File
, 'rb')
527 Data
= cPickle
.load(Fd
)
529 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
536 ## Retrieve and cache the real path name in file system
538 # @param Root The root directory of path relative to
540 # @retval str The path string if the path exists
541 # @retval None If path doesn't exist
547 def __init__(self
, Root
):
549 for F
in os
.listdir(Root
):
551 self
._UPPER
_CACHE
_[F
.upper()] = F
554 def __getitem__(self
, Path
):
555 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
558 if Path
and Path
[0] == os
.path
.sep
:
560 if Path
in self
._CACHE
_:
561 return os
.path
.join(self
._Root
, Path
)
562 UpperPath
= Path
.upper()
563 if UpperPath
in self
._UPPER
_CACHE
_:
564 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
568 SepIndex
= Path
.find(os
.path
.sep
)
570 Parent
= UpperPath
[:SepIndex
]
571 if Parent
not in self
._UPPER
_CACHE
_:
573 LastSepIndex
= SepIndex
574 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
576 if LastSepIndex
== -1:
581 SepIndex
= LastSepIndex
583 Parent
= Path
[:SepIndex
]
584 ParentKey
= UpperPath
[:SepIndex
]
585 if ParentKey
not in self
._UPPER
_CACHE
_:
589 if Parent
in self
._CACHE
_:
592 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
593 for F
in os
.listdir(ParentDir
):
594 Dir
= os
.path
.join(ParentDir
, F
)
595 self
._CACHE
_.add(Dir
)
596 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
598 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
601 if Path
in self
._CACHE
_:
602 return os
.path
.join(self
._Root
, Path
)
603 elif UpperPath
in self
._UPPER
_CACHE
_:
604 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
607 ## Get all files of a directory
609 # @param Root: Root dir
610 # @param SkipList : The files need be skipped
612 # @retval A list of all files
614 def GetFiles(Root
, SkipList
=None, FullPath
= True):
617 for Root
, Dirs
, Files
in os
.walk(Root
):
619 for Item
in SkipList
:
624 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
626 File
= File
[len(OriPath
) + 1:]
627 FileList
.append(File
)
631 ## Check if gvien file exists or not
633 # @param File File name or path to be checked
634 # @param Dir The directory the file is relative to
636 # @retval True if file exists
637 # @retval False if file doesn't exists
639 def ValidFile(File
, Ext
=None):
641 Dummy
, FileExt
= os
.path
.splitext(File
)
642 if FileExt
.lower() != Ext
.lower():
644 if not os
.path
.exists(File
):
648 def RealPath(File
, Dir
='', OverrideDir
=''):
649 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
650 NewFile
= GlobalData
.gAllFiles
[NewFile
]
651 if not NewFile
and OverrideDir
:
652 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
653 NewFile
= GlobalData
.gAllFiles
[NewFile
]
656 def RealPath2(File
, Dir
='', OverrideDir
=''):
659 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
661 if OverrideDir
[-1] == os
.path
.sep
:
662 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
664 return NewFile
[len(OverrideDir
)+1:], NewFile
[0:len(OverrideDir
)]
665 if GlobalData
.gAllFiles
:
666 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
668 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
669 if not os
.path
.exists(NewFile
):
673 if Dir
[-1] == os
.path
.sep
:
674 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
676 return NewFile
[len(Dir
)+1:], NewFile
[0:len(Dir
)]
682 ## Check if gvien file exists or not
685 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
688 Dummy
, FileExt
= os
.path
.splitext(File
)
689 if FileExt
.lower() != Ext
.lower():
692 # Replace the Edk macros
693 if OverrideDir
!= '' and OverrideDir
!= None:
694 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
695 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
696 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
697 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
699 # Replace the default dir to current dir
702 Dir
= Dir
[len(Workspace
)+1:]
704 # First check if File has Edk definition itself
705 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
706 NewFile
= File
.replace('$(EFI_SOURCE)', EfiSource
)
707 NewFile
= NewFile
.replace('$(EDK_SOURCE)', EdkSource
)
708 NewFile
= AllFiles
[os
.path
.normpath(NewFile
)]
712 # Second check the path with override value
713 if OverrideDir
!= '' and OverrideDir
!= None:
714 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
718 # Last check the path with normal definitions
719 File
= os
.path
.join(Dir
, File
)
720 NewFile
= AllFiles
[os
.path
.normpath(File
)]
726 ## Check if gvien file exists or not
729 def ValidFile3(AllFiles
, File
, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
730 # Replace the Edk macros
731 if OverrideDir
!= '' and OverrideDir
!= None:
732 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
733 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
734 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
735 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
737 # Replace the default dir to current dir
738 # Dir is current module dir related to workspace
741 Dir
= Dir
[len(Workspace
)+1:]
744 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
745 NewRelaPath
= RelaPath
748 # First check if File has Edk definition itself
749 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
750 File
= File
.replace('$(EFI_SOURCE)', EfiSource
)
751 File
= File
.replace('$(EDK_SOURCE)', EdkSource
)
752 NewFile
= AllFiles
[os
.path
.normpath(File
)]
754 NewRelaPath
= os
.path
.dirname(NewFile
)
755 File
= os
.path
.basename(NewFile
)
756 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
759 # Second check the path with override value
760 if OverrideDir
!= '' and OverrideDir
!= None:
761 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
763 #NewRelaPath = os.path.dirname(NewFile)
764 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
767 # Last check the path with normal definitions
768 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
775 return NewRelaPath
, RelaPath
, File
778 def GetRelPath(Path1
, Path2
):
779 FileName
= os
.path
.basename(Path2
)
780 L1
= os
.path
.normpath(Path1
).split(os
.path
.normpath('/'))
781 L2
= os
.path
.normpath(Path2
).split(os
.path
.normpath('/'))
782 for Index
in range(0, len(L1
)):
783 if L1
[Index
] != L2
[Index
]:
784 FileName
= '../' * (len(L1
) - Index
)
785 for Index2
in range(Index
, len(L2
)):
786 FileName
= os
.path
.join(FileName
, L2
[Index2
])
788 return os
.path
.normpath(FileName
)
791 ## Get GUID value from given packages
793 # @param CName The CName of the GUID
794 # @param PackageList List of packages looking-up in
796 # @retval GuidValue if the CName is found in any given package
797 # @retval None if the CName is not found in all given packages
799 def GuidValue(CName
, PackageList
):
800 for P
in PackageList
:
802 return P
.Guids
[CName
]
805 ## Get Protocol value from given packages
807 # @param CName The CName of the GUID
808 # @param PackageList List of packages looking-up in
810 # @retval GuidValue if the CName is found in any given package
811 # @retval None if the CName is not found in all given packages
813 def ProtocolValue(CName
, PackageList
):
814 for P
in PackageList
:
815 if CName
in P
.Protocols
:
816 return P
.Protocols
[CName
]
819 ## Get PPI value from given packages
821 # @param CName The CName of the GUID
822 # @param PackageList List of packages looking-up in
824 # @retval GuidValue if the CName is found in any given package
825 # @retval None if the CName is not found in all given packages
827 def PpiValue(CName
, PackageList
):
828 for P
in PackageList
:
833 ## A string template class
835 # This class implements a template for string replacement. A string template
836 # looks like following
838 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
840 # The string between ${BEGIN} and ${END} will be repeated as many times as the
841 # length of "placeholder_name", which is a list passed through a dict. The
842 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
843 # be not used and, in this case, the "placeholder_name" must not a list and it
844 # will just be replaced once.
846 class TemplateString(object):
847 _REPEAT_START_FLAG
= "BEGIN"
848 _REPEAT_END_FLAG
= "END"
850 class Section(object):
851 _LIST_TYPES
= [type([]), type(set()), type((0,))]
853 def __init__(self
, TemplateSection
, PlaceHolderList
):
854 self
._Template
= TemplateSection
855 self
._PlaceHolderList
= []
857 # Split the section into sub-sections according to the position of placeholders
859 self
._SubSectionList
= []
862 # The placeholders passed in must be in the format of
864 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
866 for PlaceHolder
,Start
,End
in PlaceHolderList
:
867 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
868 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
869 self
._PlaceHolderList
.append(PlaceHolder
)
870 SubSectionStart
= End
871 if SubSectionStart
< len(TemplateSection
):
872 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
874 self
._SubSectionList
= [TemplateSection
]
877 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
879 def Instantiate(self
, PlaceHolderValues
):
881 RepeatPlaceHolders
= {}
882 NonRepeatPlaceHolders
= {}
884 for PlaceHolder
in self
._PlaceHolderList
:
885 if PlaceHolder
not in PlaceHolderValues
:
887 Value
= PlaceHolderValues
[PlaceHolder
]
888 if type(Value
) in self
._LIST
_TYPES
:
890 RepeatTime
= len(Value
)
891 elif RepeatTime
!= len(Value
):
895 "${%s} has different repeat time from others!" % PlaceHolder
,
896 ExtraData
=str(self
._Template
)
898 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
900 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
902 if NonRepeatPlaceHolders
:
904 for S
in self
._SubSectionList
:
905 if S
not in NonRepeatPlaceHolders
:
908 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
910 StringList
= self
._SubSectionList
912 if RepeatPlaceHolders
:
914 for Index
in range(RepeatTime
):
916 if S
not in RepeatPlaceHolders
:
917 TempStringList
.append(S
)
919 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
920 StringList
= TempStringList
922 return "".join(StringList
)
925 def __init__(self
, Template
=None):
927 self
.IsBinary
= False
928 self
._Template
= Template
929 self
._TemplateSectionList
= self
._Parse
(Template
)
933 # @retval string The string replaced
938 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
940 # @retval list A list of TemplateString.Section objects
942 def _Parse(self
, Template
):
947 TemplateSectionList
= []
949 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
951 if MatchEnd
<= len(Template
):
952 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
953 TemplateSectionList
.append(TemplateSection
)
956 MatchString
= MatchObj
.group(1)
957 MatchStart
= MatchObj
.start()
958 MatchEnd
= MatchObj
.end()
960 if MatchString
== self
._REPEAT
_START
_FLAG
:
961 if MatchStart
> SectionStart
:
962 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
963 TemplateSectionList
.append(TemplateSection
)
964 SectionStart
= MatchEnd
966 elif MatchString
== self
._REPEAT
_END
_FLAG
:
967 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
968 TemplateSectionList
.append(TemplateSection
)
969 SectionStart
= MatchEnd
972 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
973 SearchFrom
= MatchEnd
974 return TemplateSectionList
976 ## Replace the string template with dictionary of placeholders and append it to previous one
978 # @param AppendString The string template to append
979 # @param Dictionary The placeholder dictionaries
981 def Append(self
, AppendString
, Dictionary
=None):
983 SectionList
= self
._Parse
(AppendString
)
984 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
986 self
.String
+= AppendString
988 ## Replace the string template with dictionary of placeholders
990 # @param Dictionary The placeholder dictionaries
992 # @retval str The string replaced with placeholder values
994 def Replace(self
, Dictionary
=None):
995 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
997 ## Progress indicator class
999 # This class makes use of thread to print progress on console.
1002 # for avoiding deadloop
1004 _ProgressThread
= None
1005 _CheckInterval
= 0.25
1009 # @param OpenMessage The string printed before progress charaters
1010 # @param CloseMessage The string printed after progress charaters
1011 # @param ProgressChar The charater used to indicate the progress
1012 # @param Interval The interval in seconds between two progress charaters
1014 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
1015 self
.PromptMessage
= OpenMessage
1016 self
.CodaMessage
= CloseMessage
1017 self
.ProgressChar
= ProgressChar
1018 self
.Interval
= Interval
1019 if Progressor
._StopFlag
== None:
1020 Progressor
._StopFlag
= threading
.Event()
1022 ## Start to print progress charater
1024 # @param OpenMessage The string printed before progress charaters
1026 def Start(self
, OpenMessage
=None):
1027 if OpenMessage
!= None:
1028 self
.PromptMessage
= OpenMessage
1029 Progressor
._StopFlag
.clear()
1030 if Progressor
._ProgressThread
== None:
1031 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
1032 Progressor
._ProgressThread
.setDaemon(False)
1033 Progressor
._ProgressThread
.start()
1035 ## Stop printing progress charater
1037 # @param CloseMessage The string printed after progress charaters
1039 def Stop(self
, CloseMessage
=None):
1040 OriginalCodaMessage
= self
.CodaMessage
1041 if CloseMessage
!= None:
1042 self
.CodaMessage
= CloseMessage
1044 self
.CodaMessage
= OriginalCodaMessage
1046 ## Thread entry method
1047 def _ProgressThreadEntry(self
):
1048 sys
.stdout
.write(self
.PromptMessage
+ " ")
1051 while not Progressor
._StopFlag
.isSet():
1053 sys
.stdout
.write(self
.ProgressChar
)
1055 TimeUp
= self
.Interval
1056 time
.sleep(self
._CheckInterval
)
1057 TimeUp
-= self
._CheckInterval
1058 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
1061 ## Abort the progress display
1064 if Progressor
._StopFlag
!= None:
1065 Progressor
._StopFlag
.set()
1066 if Progressor
._ProgressThread
!= None:
1067 Progressor
._ProgressThread
.join()
1068 Progressor
._ProgressThread
= None
1070 ## A dict which can access its keys and/or values orderly
1072 # The class implements a new kind of dict which its keys or values can be
1073 # accessed in the order they are added into the dict. It guarantees the order
1074 # by making use of an internal list to keep a copy of keys.
1076 class sdict(IterableUserDict
):
1079 IterableUserDict
.__init
__(self
)
1083 def __setitem__(self
, key
, value
):
1084 if key
not in self
._key
_list
:
1085 self
._key
_list
.append(key
)
1086 IterableUserDict
.__setitem
__(self
, key
, value
)
1089 def __delitem__(self
, key
):
1090 self
._key
_list
.remove(key
)
1091 IterableUserDict
.__delitem
__(self
, key
)
1093 ## used in "for k in dict" loop to ensure the correct order
1095 return self
.iterkeys()
1099 return len(self
._key
_list
)
1101 ## "in" test support
1102 def __contains__(self
, key
):
1103 return key
in self
._key
_list
1106 def index(self
, key
):
1107 return self
._key
_list
.index(key
)
1110 def insert(self
, key
, newkey
, newvalue
, order
):
1111 index
= self
._key
_list
.index(key
)
1112 if order
== 'BEFORE':
1113 self
._key
_list
.insert(index
, newkey
)
1114 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1115 elif order
== 'AFTER':
1116 self
._key
_list
.insert(index
+ 1, newkey
)
1117 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1120 def append(self
, sdict
):
1122 if key
not in self
._key
_list
:
1123 self
._key
_list
.append(key
)
1124 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
1126 def has_key(self
, key
):
1127 return key
in self
._key
_list
1132 IterableUserDict
.clear(self
)
1134 ## Return a copy of keys
1137 for key
in self
._key
_list
:
1141 ## Return a copy of values
1144 for key
in self
._key
_list
:
1145 values
.append(self
[key
])
1148 ## Return a copy of (key, value) list
1151 for key
in self
._key
_list
:
1152 items
.append((key
, self
[key
]))
1155 ## Iteration support
1156 def iteritems(self
):
1157 return iter(self
.items())
1159 ## Keys interation support
1161 return iter(self
.keys())
1163 ## Values interation support
1164 def itervalues(self
):
1165 return iter(self
.values())
1167 ## Return value related to a key, and remove the (key, value) from the dict
1168 def pop(self
, key
, *dv
):
1170 if key
in self
._key
_list
:
1172 self
.__delitem
__(key
)
1177 ## Return (key, value) pair, and remove the (key, value) from the dict
1179 key
= self
._key
_list
[-1]
1181 self
.__delitem
__(key
)
1184 def update(self
, dict=None, **kwargs
):
1186 for k
, v
in dict.items():
1189 for k
, v
in kwargs
.items():
1192 ## Dictionary with restricted keys
1196 def __init__(self
, KeyList
):
1198 dict.__setitem
__(self
, Key
, "")
1201 def __setitem__(self
, key
, value
):
1203 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1204 ExtraData
=", ".join(dict.keys(self
)))
1205 dict.__setitem
__(self
, key
, value
)
1208 def __getitem__(self
, key
):
1211 return dict.__getitem
__(self
, key
)
1214 def __delitem__(self
, key
):
1215 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1220 self
.__setitem
__(Key
, "")
1222 ## Return value related to a key, and remove the (key, value) from the dict
1223 def pop(self
, key
, *dv
):
1224 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1226 ## Return (key, value) pair, and remove the (key, value) from the dict
1228 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1230 ## Dictionary using prioritized list as key
1233 _ListType
= type([])
1234 _TupleType
= type(())
1235 _Wildcard
= 'COMMON'
1236 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1238 def __init__(self
, _Single_
=False, _Level_
=2):
1239 self
._Level
_ = _Level_
1241 self
._Single
_ = _Single_
1244 def __getitem__(self
, key
):
1247 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1251 elif self
._Level
_ > 1:
1252 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1255 if self
._Level
_ > 1:
1256 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1258 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1259 FirstKey
= self
._Wildcard
1262 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1264 return self
._GetAllValues
(FirstKey
, RestKeys
)
1266 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1268 #print "%s-%s" % (FirstKey, self._Level_) ,
1269 if self
._Level
_ > 1:
1270 if FirstKey
== self
._Wildcard
:
1271 if FirstKey
in self
.data
:
1272 Value
= self
.data
[FirstKey
][RestKeys
]
1274 for Key
in self
.data
:
1275 Value
= self
.data
[Key
][RestKeys
]
1276 if Value
!= None: break
1278 if FirstKey
in self
.data
:
1279 Value
= self
.data
[FirstKey
][RestKeys
]
1280 if Value
== None and self
._Wildcard
in self
.data
:
1282 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1284 if FirstKey
== self
._Wildcard
:
1285 if FirstKey
in self
.data
:
1286 Value
= self
.data
[FirstKey
]
1288 for Key
in self
.data
:
1289 Value
= self
.data
[Key
]
1290 if Value
!= None: break
1292 if FirstKey
in self
.data
:
1293 Value
= self
.data
[FirstKey
]
1294 elif self
._Wildcard
in self
.data
:
1295 Value
= self
.data
[self
._Wildcard
]
1298 def _GetAllValues(self
, FirstKey
, RestKeys
):
1300 if self
._Level
_ > 1:
1301 if FirstKey
== self
._Wildcard
:
1302 for Key
in self
.data
:
1303 Value
+= self
.data
[Key
][RestKeys
]
1305 if FirstKey
in self
.data
:
1306 Value
+= self
.data
[FirstKey
][RestKeys
]
1307 if self
._Wildcard
in self
.data
:
1308 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1310 if FirstKey
== self
._Wildcard
:
1311 for Key
in self
.data
:
1312 Value
.append(self
.data
[Key
])
1314 if FirstKey
in self
.data
:
1315 Value
.append(self
.data
[FirstKey
])
1316 if self
._Wildcard
in self
.data
:
1317 Value
.append(self
.data
[self
._Wildcard
])
1321 def __setitem__(self
, key
, value
):
1324 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1329 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1332 if self
._Level
_ > 1:
1333 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1335 if FirstKey
in self
._ValidWildcardList
:
1336 FirstKey
= self
._Wildcard
1338 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1339 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1341 if self
._Level
_ > 1:
1342 self
.data
[FirstKey
][RestKeys
] = value
1344 self
.data
[FirstKey
] = value
1346 def SetGreedyMode(self
):
1347 self
._Single
_ = False
1348 if self
._Level
_ > 1:
1349 for Key
in self
.data
:
1350 self
.data
[Key
].SetGreedyMode()
1352 def SetSingleMode(self
):
1353 self
._Single
_ = True
1354 if self
._Level
_ > 1:
1355 for Key
in self
.data
:
1356 self
.data
[Key
].SetSingleMode()
1358 def GetKeys(self
, KeyIndex
=0):
1359 assert KeyIndex
>= 0
1361 return set(self
.data
.keys())
1364 for Key
in self
.data
:
1365 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1368 ## Boolean chain list
1370 class Blist(UserList
):
1371 def __init__(self
, initlist
=None):
1372 UserList
.__init
__(self
, initlist
)
1373 def __setitem__(self
, i
, item
):
1374 if item
not in [True, False]:
1380 def _GetResult(self
):
1382 for item
in self
.data
:
1385 Result
= property(_GetResult
)
1387 def ParseConsoleLog(Filename
):
1388 Opr
= open(os
.path
.normpath(Filename
), 'r')
1389 Opw
= open(os
.path
.normpath(Filename
+ '.New'), 'w+')
1390 for Line
in Opr
.readlines():
1391 if Line
.find('.efi') > -1:
1392 Line
= Line
[Line
.rfind(' ') : Line
.rfind('.efi')].strip()
1393 Opw
.write('%s\n' % Line
)
1400 # Analyze DSC PCD value, since there is no data type info in DSC
1401 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1402 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1403 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1404 # 3. Dynamic default:
1405 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1406 # TokenSpace.PcdCName|PcdValue
1408 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1409 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1411 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1412 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1413 # there might have "|" operator, also in string value.
1415 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1416 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1417 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1419 # ValueList: A List contain fields described above
1420 # IsValid: True if conforming EBNF, otherwise False
1421 # Index: The index where PcdValue is in ValueList
1423 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1424 Setting
= Setting
.strip()
1425 # There might be escaped quote in a string: \", \\\"
1426 Data
= Setting
.replace('\\\\', '//').replace('\\\"', '\\\'')
1427 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1434 elif ch
== '(' and not InStr
:
1436 elif ch
== ')' and not InStr
:
1439 if (Pair
> 0 or InStr
) and ch
== TAB_VALUE_SPLIT
:
1446 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1448 FieldList
.append(Setting
[StartPos
:].strip())
1450 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1454 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1455 Value
= FieldList
[0]
1457 if len(FieldList
) > 1:
1459 # Fix the PCD type when no DataType input
1464 if len(FieldList
) > 2:
1466 if DataType
== 'VOID*':
1467 IsValid
= (len(FieldList
) <= 3)
1469 IsValid
= (len(FieldList
) <= 1)
1470 return [Value
, '', Size
], IsValid
, 0
1471 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1472 Value
= FieldList
[0]
1474 if len(FieldList
) > 1:
1478 if len(FieldList
) > 2:
1482 if Value
.startswith("L"):
1483 Size
= str((len(Value
)- 3 + 1) * 2)
1484 elif Value
.startswith("{"):
1485 Size
= str(len(Value
.split(",")))
1487 Size
= str(len(Value
) -2 + 1 )
1488 if DataType
== 'VOID*':
1489 IsValid
= (len(FieldList
) <= 3)
1491 IsValid
= (len(FieldList
) <= 1)
1492 return [Value
, Type
, Size
], IsValid
, 0
1493 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1494 VpdOffset
= FieldList
[0]
1496 if not DataType
== 'VOID*':
1497 if len(FieldList
) > 1:
1498 Value
= FieldList
[1]
1500 if len(FieldList
) > 1:
1502 if len(FieldList
) > 2:
1503 Value
= FieldList
[2]
1504 if DataType
== 'VOID*':
1505 IsValid
= (len(FieldList
) <= 3)
1507 IsValid
= (len(FieldList
) <= 2)
1508 return [VpdOffset
, Size
, Value
], IsValid
, 2
1509 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1510 HiiString
= FieldList
[0]
1511 Guid
= Offset
= Value
= ''
1512 if len(FieldList
) > 1:
1514 if len(FieldList
) > 2:
1515 Offset
= FieldList
[2]
1516 if len(FieldList
) > 3:
1517 Value
= FieldList
[3]
1518 IsValid
= (3 <= len(FieldList
) <= 4)
1519 return [HiiString
, Guid
, Offset
, Value
], IsValid
, 3
1524 # Analyze the pcd Value, Datum type and TokenNumber.
1525 # Used to avoid split issue while the value string contain "|" character
1527 # @param[in] Setting: A String contain value/datum type/token number information;
1529 # @retval ValueList: A List contain value, datum type and toke number.
1531 def AnalyzePcdData(Setting
):
1532 ValueList
= ['', '', '']
1534 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1535 PtrValue
= ValueRe
.findall(Setting
)
1537 ValueUpdateFlag
= False
1539 if len(PtrValue
) >= 1:
1540 Setting
= re
.sub(ValueRe
, '', Setting
)
1541 ValueUpdateFlag
= True
1543 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1544 ValueList
[0:len(TokenList
)] = TokenList
1547 ValueList
[0] = PtrValue
[0]
1551 ## AnalyzeHiiPcdData
1553 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1554 # Used to avoid split issue while the value string contain "|" character
1556 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1558 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1560 def AnalyzeHiiPcdData(Setting
):
1561 ValueList
= ['', '', '', '']
1563 TokenList
= GetSplitValueList(Setting
)
1564 ValueList
[0:len(TokenList
)] = TokenList
1568 ## AnalyzeVpdPcdData
1570 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1571 # Used to avoid split issue while the value string contain "|" character
1573 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1575 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1577 def AnalyzeVpdPcdData(Setting
):
1578 ValueList
= ['', '', '']
1580 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1581 PtrValue
= ValueRe
.findall(Setting
)
1583 ValueUpdateFlag
= False
1585 if len(PtrValue
) >= 1:
1586 Setting
= re
.sub(ValueRe
, '', Setting
)
1587 ValueUpdateFlag
= True
1589 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1590 ValueList
[0:len(TokenList
)] = TokenList
1593 ValueList
[2] = PtrValue
[0]
1597 ## check format of PCD value against its the datum type
1599 # For PCD value setting
1601 def CheckPcdDatum(Type
, Value
):
1603 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1604 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1605 or (Value
.startswith('{') and Value
.endswith('}'))
1607 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1608 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1609 elif ValueRe
.match(Value
):
1610 # Check the chars in UnicodeString or CString is printable
1611 if Value
.startswith("L"):
1615 Printset
= set(string
.printable
)
1616 Printset
.remove(TAB_PRINTCHAR_VT
)
1617 Printset
.add(TAB_PRINTCHAR_BS
)
1618 Printset
.add(TAB_PRINTCHAR_NUL
)
1619 if not set(Value
).issubset(Printset
):
1620 PrintList
= list(Printset
)
1622 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1623 elif Type
== 'BOOLEAN':
1624 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1625 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1626 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1627 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1629 Value
= long(Value
, 0)
1631 return False, "Invalid value [%s] of type [%s];"\
1632 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1634 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type
)
1638 ## Split command line option string to list
1640 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1641 # in non-windows platform to launch command
1643 def SplitOption(OptionString
):
1648 for Index
in range(0, len(OptionString
)):
1649 CurrentChar
= OptionString
[Index
]
1650 if CurrentChar
in ['"', "'"]:
1651 if QuotationMark
== CurrentChar
:
1653 elif QuotationMark
== "":
1654 QuotationMark
= CurrentChar
1659 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1660 if Index
> OptionStart
:
1661 OptionList
.append(OptionString
[OptionStart
:Index
-1])
1663 LastChar
= CurrentChar
1664 OptionList
.append(OptionString
[OptionStart
:])
1667 def CommonPath(PathList
):
1668 P1
= min(PathList
).split(os
.path
.sep
)
1669 P2
= max(PathList
).split(os
.path
.sep
)
1670 for Index
in xrange(min(len(P1
), len(P2
))):
1671 if P1
[Index
] != P2
[Index
]:
1672 return os
.path
.sep
.join(P1
[:Index
])
1673 return os
.path
.sep
.join(P1
)
1676 # Convert string to C format array
1678 def ConvertStringToByteArray(Value
):
1679 Value
= Value
.strip()
1683 if not Value
.endswith('}'):
1685 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1686 ValFields
= Value
.split(',')
1688 for Index
in range(len(ValFields
)):
1689 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1692 Value
= '{' + ','.join(ValFields
) + '}'
1696 if Value
.startswith('L"'):
1697 if not Value
.endswith('"'):
1701 elif not Value
.startswith('"') or not Value
.endswith('"'):
1704 Value
= eval(Value
) # translate escape character
1706 for Index
in range(0,len(Value
)):
1708 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1710 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1711 Value
= NewValue
+ '0}'
1714 class PathClass(object):
1715 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1716 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1718 self
.File
= str(File
)
1719 if os
.path
.isabs(self
.File
):
1723 self
.Root
= str(Root
)
1724 self
.AlterRoot
= str(AlterRoot
)
1726 # Remove any '.' and '..' in path
1728 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1729 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1730 # eliminate the side-effect of 'C:'
1731 if self
.Root
[-1] == ':':
1732 self
.Root
+= os
.path
.sep
1733 # file path should not start with path separator
1734 if self
.Root
[-1] == os
.path
.sep
:
1735 self
.File
= self
.Path
[len(self
.Root
):]
1737 self
.File
= self
.Path
[len(self
.Root
)+1:]
1739 self
.Path
= os
.path
.normpath(self
.File
)
1741 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1742 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1746 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1748 self
.Dir
= self
.Root
1750 self
.Dir
= self
.SubDir
1755 self
.Type
= self
.Ext
.lower()
1757 self
.IsBinary
= IsBinary
1758 self
.Target
= Target
1759 self
.TagName
= TagName
1760 self
.ToolCode
= ToolCode
1761 self
.ToolChainFamily
= ToolChainFamily
1765 ## Convert the object of this class to a string
1767 # Convert member Path of the class to a string
1769 # @retval string Formatted String
1774 ## Override __eq__ function
1776 # Check whether PathClass are the same
1778 # @retval False The two PathClass are different
1779 # @retval True The two PathClass are the same
1781 def __eq__(self
, Other
):
1782 if type(Other
) == type(self
):
1783 return self
.Path
== Other
.Path
1785 return self
.Path
== str(Other
)
1787 ## Override __cmp__ function
1789 # Customize the comparsion operation of two PathClass
1791 # @retval 0 The two PathClass are different
1792 # @retval -1 The first PathClass is less than the second PathClass
1793 # @retval 1 The first PathClass is Bigger than the second PathClass
1794 def __cmp__(self
, Other
):
1795 if type(Other
) == type(self
):
1796 OtherKey
= Other
.Path
1798 OtherKey
= str(Other
)
1801 if SelfKey
== OtherKey
:
1803 elif SelfKey
> OtherKey
:
1808 ## Override __hash__ function
1810 # Use Path as key in hash table
1812 # @retval string Key for hash table
1815 return hash(self
.Path
)
1817 def _GetFileKey(self
):
1818 if self
._Key
== None:
1819 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1822 def _GetTimeStamp(self
):
1823 return os
.stat(self
.Path
)[8]
1825 def Validate(self
, Type
='', CaseSensitive
=True):
1826 if GlobalData
.gCaseInsensitive
:
1827 CaseSensitive
= False
1828 if Type
and Type
.lower() != self
.Type
:
1829 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1831 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1832 if not RealRoot
and not RealFile
:
1833 RealFile
= self
.File
1835 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1837 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1838 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1842 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1843 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1844 ErrorCode
= FILE_CASE_MISMATCH
1845 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1847 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1848 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1850 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1853 self
.File
= RealFile
1854 self
.Root
= RealRoot
1855 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1856 return ErrorCode
, ErrorInfo
1858 Key
= property(_GetFileKey
)
1859 TimeStamp
= property(_GetTimeStamp
)
1861 ## Parse PE image to get the required PE informaion.
1863 class PeImageClass():
1866 # @param File FilePath of PeImage
1868 def __init__(self
, PeFile
):
1869 self
.FileName
= PeFile
1870 self
.IsValid
= False
1873 self
.SectionAlignment
= 0
1874 self
.SectionHeaderList
= []
1877 PeObject
= open(PeFile
, 'rb')
1879 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1882 ByteArray
= array
.array('B')
1883 ByteArray
.fromfile(PeObject
, 0x3E)
1884 ByteList
= ByteArray
.tolist()
1885 # DOS signature should be 'MZ'
1886 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1887 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1890 # Read 4 byte PE Signature
1891 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1892 PeObject
.seek(PeOffset
)
1893 ByteArray
= array
.array('B')
1894 ByteArray
.fromfile(PeObject
, 4)
1895 # PE signature should be 'PE\0\0'
1896 if ByteArray
.tostring() != 'PE\0\0':
1897 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1900 # Read PE file header
1901 ByteArray
= array
.array('B')
1902 ByteArray
.fromfile(PeObject
, 0x14)
1903 ByteList
= ByteArray
.tolist()
1904 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1906 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1909 # Read PE optional header
1910 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1911 ByteArray
= array
.array('B')
1912 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1913 ByteList
= ByteArray
.tolist()
1914 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1915 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1916 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1918 # Read each Section Header
1919 for Index
in range(SecNumber
):
1920 ByteArray
= array
.array('B')
1921 ByteArray
.fromfile(PeObject
, 0x28)
1922 ByteList
= ByteArray
.tolist()
1923 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1924 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1925 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1926 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1927 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1931 def _ByteListToStr(self
, ByteList
):
1933 for index
in range(len(ByteList
)):
1934 if ByteList
[index
] == 0:
1936 String
+= chr(ByteList
[index
])
1939 def _ByteListToInt(self
, ByteList
):
1941 for index
in range(len(ByteList
) - 1, -1, -1):
1942 Value
= (Value
<< 8) |
int(ByteList
[index
])
1952 def __init__(self
,SkuIdentifier
='', SkuIds
={}):
1954 self
.AvailableSkuIds
= sdict()
1957 if SkuIdentifier
== '' or SkuIdentifier
is None:
1958 self
.SkuIdSet
= ['DEFAULT']
1959 elif SkuIdentifier
== 'ALL':
1960 self
.SkuIdSet
= SkuIds
.keys()
1962 r
= SkuIdentifier
.split('|')
1963 self
.SkuIdSet
=[r
[k
].strip() for k
in range(len(r
))]
1964 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
and SkuIdentifier
!= 'ALL':
1965 self
.SkuIdSet
.remove('DEFAULT')
1967 for each
in self
.SkuIdSet
:
1969 self
.AvailableSkuIds
[each
] = SkuIds
[each
]
1971 EdkLogger
.error("build", PARAMETER_INVALID
,
1972 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1973 % (each
, " ".join(SkuIds
.keys())))
1975 def __SkuUsageType(self
):
1977 if len(self
.SkuIdSet
) == 1:
1978 if self
.SkuIdSet
[0] == 'DEFAULT':
1979 return SkuClass
.DEFAULT
1981 return SkuClass
.SINGLE
1983 return SkuClass
.MULTIPLE
1985 def __GetAvailableSkuIds(self
):
1986 return self
.AvailableSkuIds
1988 def __GetSystemSkuID(self
):
1989 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
1990 return self
.SkuIdSet
[0]
1994 SystemSkuId
= property(__GetSystemSkuID
)
1995 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
1996 SkuUsageType
= property(__SkuUsageType
)
2000 # This acts like the main() function for the script, unless it is 'import'ed into another
2003 if __name__
== '__main__':