2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 import Common
.LongFilePathOs
as os
27 from struct
import pack
28 from UserDict
import IterableUserDict
29 from UserList
import UserList
31 from Common
import EdkLogger
as EdkLogger
32 from Common
import GlobalData
as GlobalData
33 from DataType
import *
34 from BuildToolError
import *
35 from CommonDataClass
.DataClass
import *
36 from Parsing
import GetSplitValueList
37 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
38 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
40 ## Regular expression used to find out place holders in string template
41 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE | re
.UNICODE
)
43 ## Dictionary used to store file time stamp for quick re-access
44 gFileTimeStampCache
= {} # {file path : file time stamp}
46 ## Dictionary used to store dependencies of files
47 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
49 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
50 """ Parse map file to get variable offset in current EFI file
51 @param mapfilepath Map file absolution path
52 @param efifilepath: EFI binary file full path
53 @param varnames iteratable container whose elements are variable names to be searched
55 @return List whos elements are tuple with variable name and raw offset
59 f
= open(mapfilepath
, 'r')
65 if len(lines
) == 0: return None
66 firstline
= lines
[0].strip()
67 if (firstline
.startswith("Archive member included ") and
68 firstline
.endswith(" file (symbol)")):
69 return _parseForGCC(lines
, efifilepath
, varnames
)
70 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
:
97 m
= re
.match("^.data.(%s)" % varname
, line
)
99 m
= re
.match(".data.(%s)$" % varname
, line
)
101 Str
= lines
[index
+ 1]
103 Str
= line
[len(".data.%s" % varname
):]
105 m
= re
.match('^([\da-fA-Fx]+) +([\da-fA-Fx]+)', Str
.strip())
107 varoffset
.append((varname
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
111 # get section information from efi file
112 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
113 if efisecs
== None or len(efisecs
) == 0:
117 for efisec
in efisecs
:
118 for section
in sections
:
119 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
120 redirection
= int(section
[1], 16) - efisec
[1]
123 for var
in varoffset
:
124 for efisec
in efisecs
:
125 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
126 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
129 def _parseGeneral(lines
, efifilepath
, varnames
):
130 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
131 secs
= [] # key = section name
133 secRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
134 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
138 if re
.match("^Start[' ']+Length[' ']+Name[' ']+Class", line
):
141 if re
.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line
):
144 if re
.match("^entry point at", line
):
147 if status
== 1 and len(line
) != 0:
148 m
= secRe
.match(line
)
149 assert m
!= None, "Fail to parse the section in map file , line is %s" % line
150 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
151 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
152 if status
== 2 and len(line
) != 0:
153 for varname
in varnames
:
154 m
= symRe
.match(line
)
155 assert m
!= None, "Fail to parse the symbol in map file, line is %s" % line
156 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
157 sec_no
= int(sec_no
, 16)
158 sym_offset
= int(sym_offset
, 16)
159 vir_addr
= int(vir_addr
, 16)
160 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
162 # fond a binary pcd entry in map file
164 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
165 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
167 if not varoffset
: return []
169 # get section information from efi file
170 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
171 if efisecs
== None or len(efisecs
) == 0:
175 for var
in varoffset
:
177 for efisec
in efisecs
:
179 if var
[1].strip() == efisec
[0].strip():
180 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
181 elif var
[4] == index
:
182 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
186 ## Routine to process duplicated INF
188 # This function is called by following two cases:
191 # Pkg/module/module.inf
192 # Pkg/module/module.inf {
194 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
197 # INF Pkg/module/module.inf
198 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
200 # This function copies Pkg/module/module.inf to
201 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
203 # @param Path Original PathClass object
204 # @param BaseName New file base name
206 # @retval return the new PathClass object
208 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
209 Filename
= os
.path
.split(Path
.File
)[1]
211 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
213 Filename
= BaseName
+ Path
.BaseName
216 # If -N is specified on command line, cache is disabled
217 # The directory has to be created
219 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
220 if not os
.path
.exists(DbDir
):
223 # A temporary INF is copied to database path which must have write permission
224 # The temporary will be removed at the end of build
225 # In case of name conflict, the file name is
226 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
228 TempFullPath
= os
.path
.join(DbDir
,
230 RtPath
= PathClass(Path
.File
, Workspace
)
232 # Modify the full path to temporary path, keep other unchanged
234 # To build same module more than once, the module path with FILE_GUID overridden has
235 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
236 # in DSC which is used as relative path by C files and other files in INF.
237 # A trick was used: all module paths are PathClass instances, after the initialization
238 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
240 # The reason for creating a temporary INF is:
241 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
242 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
243 # A different key for the same module is needed to create different output directory,
244 # retrieve overridden PCDs, library instances.
246 # The BaseName is the FILE_GUID which is also the output directory name.
249 RtPath
.Path
= TempFullPath
250 RtPath
.BaseName
= BaseName
252 # If file exists, compare contents
254 if os
.path
.exists(TempFullPath
):
255 with
open(str(Path
), 'rb') as f1
: Src
= f1
.read()
256 with
open(TempFullPath
, 'rb') as f2
: Dst
= f2
.read()
259 GlobalData
.gTempInfs
.append(TempFullPath
)
260 shutil
.copy2(str(Path
), TempFullPath
)
263 ## Remove temporary created INFs whose paths were saved in gTempInfs
265 def ClearDuplicatedInf():
266 for File
in GlobalData
.gTempInfs
:
267 if os
.path
.exists(File
):
270 ## callback routine for processing variable option
272 # This function can be used to process variable number of option values. The
273 # typical usage of it is specify architecure list on command line.
274 # (e.g. <tool> -a IA32 X64 IPF)
276 # @param Option Standard callback function parameter
277 # @param OptionString Standard callback function parameter
278 # @param Value Standard callback function parameter
279 # @param Parser Standard callback function parameter
283 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
286 RawArgs
= Parser
.rargs
289 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
290 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
294 setattr(Parser
.values
, Option
.dest
, Value
)
296 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
298 # @param Guid The GUID string
300 # @retval string The GUID string in C structure style
302 def GuidStringToGuidStructureString(Guid
):
303 GuidList
= Guid
.split('-')
305 for Index
in range(0, 3, 1):
306 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
307 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
308 for Index
in range(0, 12, 2):
309 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
313 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
315 # @param GuidValue The GUID value in byte array
317 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
319 def GuidStructureByteArrayToGuidString(GuidValue
):
320 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
321 guidValueList
= guidValueString
.split(",")
322 if len(guidValueList
) != 16:
324 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
326 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
327 int(guidValueList
[3], 16),
328 int(guidValueList
[2], 16),
329 int(guidValueList
[1], 16),
330 int(guidValueList
[0], 16),
331 int(guidValueList
[5], 16),
332 int(guidValueList
[4], 16),
333 int(guidValueList
[7], 16),
334 int(guidValueList
[6], 16),
335 int(guidValueList
[8], 16),
336 int(guidValueList
[9], 16),
337 int(guidValueList
[10], 16),
338 int(guidValueList
[11], 16),
339 int(guidValueList
[12], 16),
340 int(guidValueList
[13], 16),
341 int(guidValueList
[14], 16),
342 int(guidValueList
[15], 16)
347 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
349 # @param GuidValue The GUID value in C structure format
351 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
353 def GuidStructureStringToGuidString(GuidValue
):
354 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
355 guidValueList
= guidValueString
.split(",")
356 if len(guidValueList
) != 11:
358 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
360 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
361 int(guidValueList
[0], 16),
362 int(guidValueList
[1], 16),
363 int(guidValueList
[2], 16),
364 int(guidValueList
[3], 16),
365 int(guidValueList
[4], 16),
366 int(guidValueList
[5], 16),
367 int(guidValueList
[6], 16),
368 int(guidValueList
[7], 16),
369 int(guidValueList
[8], 16),
370 int(guidValueList
[9], 16),
371 int(guidValueList
[10], 16)
376 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
378 # @param GuidValue The GUID value in C structure format
380 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
382 def GuidStructureStringToGuidValueName(GuidValue
):
383 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
384 guidValueList
= guidValueString
.split(",")
385 if len(guidValueList
) != 11:
386 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
387 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
388 int(guidValueList
[0], 16),
389 int(guidValueList
[1], 16),
390 int(guidValueList
[2], 16),
391 int(guidValueList
[3], 16),
392 int(guidValueList
[4], 16),
393 int(guidValueList
[5], 16),
394 int(guidValueList
[6], 16),
395 int(guidValueList
[7], 16),
396 int(guidValueList
[8], 16),
397 int(guidValueList
[9], 16),
398 int(guidValueList
[10], 16)
401 ## Create directories
403 # @param Directory The directory name
405 def CreateDirectory(Directory
):
406 if Directory
== None or Directory
.strip() == "":
409 if not os
.access(Directory
, os
.F_OK
):
410 os
.makedirs(Directory
)
415 ## Remove directories, including files and sub-directories in it
417 # @param Directory The directory name
419 def RemoveDirectory(Directory
, Recursively
=False):
420 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
423 CurrentDirectory
= os
.getcwd()
425 for File
in os
.listdir("."):
426 if os
.path
.isdir(File
):
427 RemoveDirectory(File
, Recursively
)
430 os
.chdir(CurrentDirectory
)
433 ## Check if given file is changed or not
435 # This method is used to check if a file is changed or not between two build
436 # actions. It makes use a cache to store files timestamp.
438 # @param File The path of file
440 # @retval True If the given file is changed, doesn't exist, or can't be
441 # found in timestamp cache
442 # @retval False If the given file is changed
445 if not os
.path
.exists(File
):
448 FileState
= os
.stat(File
)
449 TimeStamp
= FileState
[-2]
451 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
455 gFileTimeStampCache
[File
] = TimeStamp
459 ## Store content in file
461 # This method is used to save file only when its content is changed. This is
462 # quite useful for "make" system to decide what will be re-built and what won't.
464 # @param File The path of file
465 # @param Content The new content of the file
466 # @param IsBinaryFile The flag indicating if the file is binary file or not
468 # @retval True If the file content is changed and the file is renewed
469 # @retval False If the file content is the same
471 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
473 Content
= Content
.replace("\n", os
.linesep
)
475 if os
.path
.exists(File
):
477 if Content
== open(File
, "rb").read():
480 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
482 DirName
= os
.path
.dirname(File
)
483 if not CreateDirectory(DirName
):
484 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
487 DirName
= os
.getcwd()
488 if not os
.access(DirName
, os
.W_OK
):
489 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
492 if GlobalData
.gIsWindows
:
494 from PyUtility
import SaveFileToDisk
495 if not SaveFileToDisk(File
, Content
):
496 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
498 Fd
= open(File
, "wb")
502 Fd
= open(File
, "wb")
506 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
510 ## Make a Python object persistent on file system
512 # @param Data The object to be stored in file
513 # @param File The path of file to store the object
515 def DataDump(Data
, File
):
518 Fd
= open(File
, 'wb')
519 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
521 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
526 ## Restore a Python object from a file
528 # @param File The path of file stored the object
530 # @retval object A python object
531 # @retval None If failure in file operation
533 def DataRestore(File
):
537 Fd
= open(File
, 'rb')
538 Data
= cPickle
.load(Fd
)
540 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
547 ## Retrieve and cache the real path name in file system
549 # @param Root The root directory of path relative to
551 # @retval str The path string if the path exists
552 # @retval None If path doesn't exist
558 def __init__(self
, Root
):
560 for F
in os
.listdir(Root
):
562 self
._UPPER
_CACHE
_[F
.upper()] = F
565 def __getitem__(self
, Path
):
566 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
569 if Path
and Path
[0] == os
.path
.sep
:
571 if Path
in self
._CACHE
_:
572 return os
.path
.join(self
._Root
, Path
)
573 UpperPath
= Path
.upper()
574 if UpperPath
in self
._UPPER
_CACHE
_:
575 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
579 SepIndex
= Path
.find(os
.path
.sep
)
581 Parent
= UpperPath
[:SepIndex
]
582 if Parent
not in self
._UPPER
_CACHE
_:
584 LastSepIndex
= SepIndex
585 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
587 if LastSepIndex
== -1:
592 SepIndex
= LastSepIndex
594 Parent
= Path
[:SepIndex
]
595 ParentKey
= UpperPath
[:SepIndex
]
596 if ParentKey
not in self
._UPPER
_CACHE
_:
600 if Parent
in self
._CACHE
_:
603 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
604 for F
in os
.listdir(ParentDir
):
605 Dir
= os
.path
.join(ParentDir
, F
)
606 self
._CACHE
_.add(Dir
)
607 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
609 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
612 if Path
in self
._CACHE
_:
613 return os
.path
.join(self
._Root
, Path
)
614 elif UpperPath
in self
._UPPER
_CACHE
_:
615 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
618 ## Get all files of a directory
620 # @param Root: Root dir
621 # @param SkipList : The files need be skipped
623 # @retval A list of all files
625 def GetFiles(Root
, SkipList
=None, FullPath
=True):
628 for Root
, Dirs
, Files
in os
.walk(Root
):
630 for Item
in SkipList
:
635 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
637 File
= File
[len(OriPath
) + 1:]
638 FileList
.append(File
)
642 ## Check if gvien file exists or not
644 # @param File File name or path to be checked
645 # @param Dir The directory the file is relative to
647 # @retval True if file exists
648 # @retval False if file doesn't exists
650 def ValidFile(File
, Ext
=None):
652 Dummy
, FileExt
= os
.path
.splitext(File
)
653 if FileExt
.lower() != Ext
.lower():
655 if not os
.path
.exists(File
):
659 def RealPath(File
, Dir
='', OverrideDir
=''):
660 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
661 NewFile
= GlobalData
.gAllFiles
[NewFile
]
662 if not NewFile
and OverrideDir
:
663 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
664 NewFile
= GlobalData
.gAllFiles
[NewFile
]
667 def RealPath2(File
, Dir
='', OverrideDir
=''):
670 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
672 if OverrideDir
[-1] == os
.path
.sep
:
673 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
675 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
676 if GlobalData
.gAllFiles
:
677 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
679 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
680 if not os
.path
.exists(NewFile
):
684 if Dir
[-1] == os
.path
.sep
:
685 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
687 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
693 ## Check if gvien file exists or not
696 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
699 Dummy
, FileExt
= os
.path
.splitext(File
)
700 if FileExt
.lower() != Ext
.lower():
703 # Replace the Edk macros
704 if OverrideDir
!= '' and OverrideDir
!= None:
705 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
706 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
707 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
708 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
710 # Replace the default dir to current dir
713 Dir
= Dir
[len(Workspace
) + 1:]
715 # First check if File has Edk definition itself
716 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
717 NewFile
= File
.replace('$(EFI_SOURCE)', EfiSource
)
718 NewFile
= NewFile
.replace('$(EDK_SOURCE)', EdkSource
)
719 NewFile
= AllFiles
[os
.path
.normpath(NewFile
)]
723 # Second check the path with override value
724 if OverrideDir
!= '' and OverrideDir
!= None:
725 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
729 # Last check the path with normal definitions
730 File
= os
.path
.join(Dir
, File
)
731 NewFile
= AllFiles
[os
.path
.normpath(File
)]
737 ## Check if gvien file exists or not
740 def ValidFile3(AllFiles
, File
, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
741 # Replace the Edk macros
742 if OverrideDir
!= '' and OverrideDir
!= None:
743 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
744 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
745 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
746 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
748 # Replace the default dir to current dir
749 # Dir is current module dir related to workspace
752 Dir
= Dir
[len(Workspace
) + 1:]
755 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
756 NewRelaPath
= RelaPath
759 # First check if File has Edk definition itself
760 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
761 File
= File
.replace('$(EFI_SOURCE)', EfiSource
)
762 File
= File
.replace('$(EDK_SOURCE)', EdkSource
)
763 NewFile
= AllFiles
[os
.path
.normpath(File
)]
765 NewRelaPath
= os
.path
.dirname(NewFile
)
766 File
= os
.path
.basename(NewFile
)
767 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
770 # Second check the path with override value
771 if OverrideDir
!= '' and OverrideDir
!= None:
772 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
774 #NewRelaPath = os.path.dirname(NewFile)
775 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
778 # Last check the path with normal definitions
779 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
786 return NewRelaPath
, RelaPath
, File
789 def GetRelPath(Path1
, Path2
):
790 FileName
= os
.path
.basename(Path2
)
791 L1
= os
.path
.normpath(Path1
).split(os
.path
.normpath('/'))
792 L2
= os
.path
.normpath(Path2
).split(os
.path
.normpath('/'))
793 for Index
in range(0, len(L1
)):
794 if L1
[Index
] != L2
[Index
]:
795 FileName
= '../' * (len(L1
) - Index
)
796 for Index2
in range(Index
, len(L2
)):
797 FileName
= os
.path
.join(FileName
, L2
[Index2
])
799 return os
.path
.normpath(FileName
)
802 ## Get GUID value from given packages
804 # @param CName The CName of the GUID
805 # @param PackageList List of packages looking-up in
806 # @param Inffile The driver file
808 # @retval GuidValue if the CName is found in any given package
809 # @retval None if the CName is not found in all given packages
811 def GuidValue(CName
, PackageList
, Inffile
= None):
812 for P
in PackageList
:
813 GuidKeys
= P
.Guids
.keys()
814 if Inffile
and P
._PrivateGuids
:
815 if not Inffile
.startswith(P
.MetaFile
.Dir
):
816 GuidKeys
= (dict.fromkeys(x
for x
in P
.Guids
if x
not in P
._PrivateGuids
)).keys()
817 if CName
in GuidKeys
:
818 return P
.Guids
[CName
]
821 ## Get Protocol value from given packages
823 # @param CName The CName of the GUID
824 # @param PackageList List of packages looking-up in
825 # @param Inffile The driver file
827 # @retval GuidValue if the CName is found in any given package
828 # @retval None if the CName is not found in all given packages
830 def ProtocolValue(CName
, PackageList
, Inffile
= None):
831 for P
in PackageList
:
832 ProtocolKeys
= P
.Protocols
.keys()
833 if Inffile
and P
._PrivateProtocols
:
834 if not Inffile
.startswith(P
.MetaFile
.Dir
):
835 ProtocolKeys
= (dict.fromkeys(x
for x
in P
.Protocols
if x
not in P
._PrivateProtocols
)).keys()
836 if CName
in ProtocolKeys
:
837 return P
.Protocols
[CName
]
840 ## Get PPI value from given packages
842 # @param CName The CName of the GUID
843 # @param PackageList List of packages looking-up in
844 # @param Inffile The driver file
846 # @retval GuidValue if the CName is found in any given package
847 # @retval None if the CName is not found in all given packages
849 def PpiValue(CName
, PackageList
, Inffile
= None):
850 for P
in PackageList
:
851 PpiKeys
= P
.Ppis
.keys()
852 if Inffile
and P
._PrivatePpis
:
853 if not Inffile
.startswith(P
.MetaFile
.Dir
):
854 PpiKeys
= (dict.fromkeys(x
for x
in P
.Ppis
if x
not in P
._PrivatePpis
)).keys()
859 ## A string template class
861 # This class implements a template for string replacement. A string template
862 # looks like following
864 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
866 # The string between ${BEGIN} and ${END} will be repeated as many times as the
867 # length of "placeholder_name", which is a list passed through a dict. The
868 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
869 # be not used and, in this case, the "placeholder_name" must not a list and it
870 # will just be replaced once.
872 class TemplateString(object):
873 _REPEAT_START_FLAG
= "BEGIN"
874 _REPEAT_END_FLAG
= "END"
876 class Section(object):
877 _LIST_TYPES
= [type([]), type(set()), type((0,))]
879 def __init__(self
, TemplateSection
, PlaceHolderList
):
880 self
._Template
= TemplateSection
881 self
._PlaceHolderList
= []
883 # Split the section into sub-sections according to the position of placeholders
885 self
._SubSectionList
= []
888 # The placeholders passed in must be in the format of
890 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
892 for PlaceHolder
, Start
, End
in PlaceHolderList
:
893 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
894 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
895 self
._PlaceHolderList
.append(PlaceHolder
)
896 SubSectionStart
= End
897 if SubSectionStart
< len(TemplateSection
):
898 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
900 self
._SubSectionList
= [TemplateSection
]
903 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
905 def Instantiate(self
, PlaceHolderValues
):
907 RepeatPlaceHolders
= {}
908 NonRepeatPlaceHolders
= {}
910 for PlaceHolder
in self
._PlaceHolderList
:
911 if PlaceHolder
not in PlaceHolderValues
:
913 Value
= PlaceHolderValues
[PlaceHolder
]
914 if type(Value
) in self
._LIST
_TYPES
:
916 RepeatTime
= len(Value
)
917 elif RepeatTime
!= len(Value
):
921 "${%s} has different repeat time from others!" % PlaceHolder
,
922 ExtraData
=str(self
._Template
)
924 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
926 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
928 if NonRepeatPlaceHolders
:
930 for S
in self
._SubSectionList
:
931 if S
not in NonRepeatPlaceHolders
:
934 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
936 StringList
= self
._SubSectionList
938 if RepeatPlaceHolders
:
940 for Index
in range(RepeatTime
):
942 if S
not in RepeatPlaceHolders
:
943 TempStringList
.append(S
)
945 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
946 StringList
= TempStringList
948 return "".join(StringList
)
951 def __init__(self
, Template
=None):
953 self
.IsBinary
= False
954 self
._Template
= Template
955 self
._TemplateSectionList
= self
._Parse
(Template
)
959 # @retval string The string replaced
964 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
966 # @retval list A list of TemplateString.Section objects
968 def _Parse(self
, Template
):
973 TemplateSectionList
= []
975 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
977 if MatchEnd
<= len(Template
):
978 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
979 TemplateSectionList
.append(TemplateSection
)
982 MatchString
= MatchObj
.group(1)
983 MatchStart
= MatchObj
.start()
984 MatchEnd
= MatchObj
.end()
986 if MatchString
== self
._REPEAT
_START
_FLAG
:
987 if MatchStart
> SectionStart
:
988 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
989 TemplateSectionList
.append(TemplateSection
)
990 SectionStart
= MatchEnd
992 elif MatchString
== self
._REPEAT
_END
_FLAG
:
993 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
994 TemplateSectionList
.append(TemplateSection
)
995 SectionStart
= MatchEnd
998 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
999 SearchFrom
= MatchEnd
1000 return TemplateSectionList
1002 ## Replace the string template with dictionary of placeholders and append it to previous one
1004 # @param AppendString The string template to append
1005 # @param Dictionary The placeholder dictionaries
1007 def Append(self
, AppendString
, Dictionary
=None):
1009 SectionList
= self
._Parse
(AppendString
)
1010 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
1012 self
.String
+= AppendString
1014 ## Replace the string template with dictionary of placeholders
1016 # @param Dictionary The placeholder dictionaries
1018 # @retval str The string replaced with placeholder values
1020 def Replace(self
, Dictionary
=None):
1021 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
1023 ## Progress indicator class
1025 # This class makes use of thread to print progress on console.
1028 # for avoiding deadloop
1030 _ProgressThread
= None
1031 _CheckInterval
= 0.25
1035 # @param OpenMessage The string printed before progress charaters
1036 # @param CloseMessage The string printed after progress charaters
1037 # @param ProgressChar The charater used to indicate the progress
1038 # @param Interval The interval in seconds between two progress charaters
1040 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
1041 self
.PromptMessage
= OpenMessage
1042 self
.CodaMessage
= CloseMessage
1043 self
.ProgressChar
= ProgressChar
1044 self
.Interval
= Interval
1045 if Progressor
._StopFlag
== None:
1046 Progressor
._StopFlag
= threading
.Event()
1048 ## Start to print progress charater
1050 # @param OpenMessage The string printed before progress charaters
1052 def Start(self
, OpenMessage
=None):
1053 if OpenMessage
!= None:
1054 self
.PromptMessage
= OpenMessage
1055 Progressor
._StopFlag
.clear()
1056 if Progressor
._ProgressThread
== None:
1057 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
1058 Progressor
._ProgressThread
.setDaemon(False)
1059 Progressor
._ProgressThread
.start()
1061 ## Stop printing progress charater
1063 # @param CloseMessage The string printed after progress charaters
1065 def Stop(self
, CloseMessage
=None):
1066 OriginalCodaMessage
= self
.CodaMessage
1067 if CloseMessage
!= None:
1068 self
.CodaMessage
= CloseMessage
1070 self
.CodaMessage
= OriginalCodaMessage
1072 ## Thread entry method
1073 def _ProgressThreadEntry(self
):
1074 sys
.stdout
.write(self
.PromptMessage
+ " ")
1077 while not Progressor
._StopFlag
.isSet():
1079 sys
.stdout
.write(self
.ProgressChar
)
1081 TimeUp
= self
.Interval
1082 time
.sleep(self
._CheckInterval
)
1083 TimeUp
-= self
._CheckInterval
1084 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
1087 ## Abort the progress display
1090 if Progressor
._StopFlag
!= None:
1091 Progressor
._StopFlag
.set()
1092 if Progressor
._ProgressThread
!= None:
1093 Progressor
._ProgressThread
.join()
1094 Progressor
._ProgressThread
= None
1096 ## A dict which can access its keys and/or values orderly
1098 # The class implements a new kind of dict which its keys or values can be
1099 # accessed in the order they are added into the dict. It guarantees the order
1100 # by making use of an internal list to keep a copy of keys.
1102 class sdict(IterableUserDict
):
1105 IterableUserDict
.__init
__(self
)
1109 def __setitem__(self
, key
, value
):
1110 if key
not in self
._key
_list
:
1111 self
._key
_list
.append(key
)
1112 IterableUserDict
.__setitem
__(self
, key
, value
)
1115 def __delitem__(self
, key
):
1116 self
._key
_list
.remove(key
)
1117 IterableUserDict
.__delitem
__(self
, key
)
1119 ## used in "for k in dict" loop to ensure the correct order
1121 return self
.iterkeys()
1125 return len(self
._key
_list
)
1127 ## "in" test support
1128 def __contains__(self
, key
):
1129 return key
in self
._key
_list
1132 def index(self
, key
):
1133 return self
._key
_list
.index(key
)
1136 def insert(self
, key
, newkey
, newvalue
, order
):
1137 index
= self
._key
_list
.index(key
)
1138 if order
== 'BEFORE':
1139 self
._key
_list
.insert(index
, newkey
)
1140 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1141 elif order
== 'AFTER':
1142 self
._key
_list
.insert(index
+ 1, newkey
)
1143 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1146 def append(self
, sdict
):
1148 if key
not in self
._key
_list
:
1149 self
._key
_list
.append(key
)
1150 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
1152 def has_key(self
, key
):
1153 return key
in self
._key
_list
1158 IterableUserDict
.clear(self
)
1160 ## Return a copy of keys
1163 for key
in self
._key
_list
:
1167 ## Return a copy of values
1170 for key
in self
._key
_list
:
1171 values
.append(self
[key
])
1174 ## Return a copy of (key, value) list
1177 for key
in self
._key
_list
:
1178 items
.append((key
, self
[key
]))
1181 ## Iteration support
1182 def iteritems(self
):
1183 return iter(self
.items())
1185 ## Keys interation support
1187 return iter(self
.keys())
1189 ## Values interation support
1190 def itervalues(self
):
1191 return iter(self
.values())
1193 ## Return value related to a key, and remove the (key, value) from the dict
1194 def pop(self
, key
, *dv
):
1196 if key
in self
._key
_list
:
1198 self
.__delitem
__(key
)
1203 ## Return (key, value) pair, and remove the (key, value) from the dict
1205 key
= self
._key
_list
[-1]
1207 self
.__delitem
__(key
)
1210 def update(self
, dict=None, **kwargs
):
1212 for k
, v
in dict.items():
1215 for k
, v
in kwargs
.items():
1218 ## Dictionary with restricted keys
1222 def __init__(self
, KeyList
):
1224 dict.__setitem
__(self
, Key
, "")
1227 def __setitem__(self
, key
, value
):
1229 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1230 ExtraData
=", ".join(dict.keys(self
)))
1231 dict.__setitem
__(self
, key
, value
)
1234 def __getitem__(self
, key
):
1237 return dict.__getitem
__(self
, key
)
1240 def __delitem__(self
, key
):
1241 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1246 self
.__setitem
__(Key
, "")
1248 ## Return value related to a key, and remove the (key, value) from the dict
1249 def pop(self
, key
, *dv
):
1250 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1252 ## Return (key, value) pair, and remove the (key, value) from the dict
1254 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1256 ## Dictionary using prioritized list as key
1259 _ListType
= type([])
1260 _TupleType
= type(())
1261 _Wildcard
= 'COMMON'
1262 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1264 def __init__(self
, _Single_
=False, _Level_
=2):
1265 self
._Level
_ = _Level_
1267 self
._Single
_ = _Single_
1270 def __getitem__(self
, key
):
1273 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1277 elif self
._Level
_ > 1:
1278 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1281 if self
._Level
_ > 1:
1282 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1284 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1285 FirstKey
= self
._Wildcard
1288 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1290 return self
._GetAllValues
(FirstKey
, RestKeys
)
1292 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1294 #print "%s-%s" % (FirstKey, self._Level_) ,
1295 if self
._Level
_ > 1:
1296 if FirstKey
== self
._Wildcard
:
1297 if FirstKey
in self
.data
:
1298 Value
= self
.data
[FirstKey
][RestKeys
]
1300 for Key
in self
.data
:
1301 Value
= self
.data
[Key
][RestKeys
]
1302 if Value
!= None: break
1304 if FirstKey
in self
.data
:
1305 Value
= self
.data
[FirstKey
][RestKeys
]
1306 if Value
== None and self
._Wildcard
in self
.data
:
1308 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1310 if FirstKey
== self
._Wildcard
:
1311 if FirstKey
in self
.data
:
1312 Value
= self
.data
[FirstKey
]
1314 for Key
in self
.data
:
1315 Value
= self
.data
[Key
]
1316 if Value
!= None: break
1318 if FirstKey
in self
.data
:
1319 Value
= self
.data
[FirstKey
]
1320 elif self
._Wildcard
in self
.data
:
1321 Value
= self
.data
[self
._Wildcard
]
1324 def _GetAllValues(self
, FirstKey
, RestKeys
):
1326 if self
._Level
_ > 1:
1327 if FirstKey
== self
._Wildcard
:
1328 for Key
in self
.data
:
1329 Value
+= self
.data
[Key
][RestKeys
]
1331 if FirstKey
in self
.data
:
1332 Value
+= self
.data
[FirstKey
][RestKeys
]
1333 if self
._Wildcard
in self
.data
:
1334 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1336 if FirstKey
== self
._Wildcard
:
1337 for Key
in self
.data
:
1338 Value
.append(self
.data
[Key
])
1340 if FirstKey
in self
.data
:
1341 Value
.append(self
.data
[FirstKey
])
1342 if self
._Wildcard
in self
.data
:
1343 Value
.append(self
.data
[self
._Wildcard
])
1347 def __setitem__(self
, key
, value
):
1350 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1355 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1358 if self
._Level
_ > 1:
1359 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1361 if FirstKey
in self
._ValidWildcardList
:
1362 FirstKey
= self
._Wildcard
1364 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1365 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1367 if self
._Level
_ > 1:
1368 self
.data
[FirstKey
][RestKeys
] = value
1370 self
.data
[FirstKey
] = value
1372 def SetGreedyMode(self
):
1373 self
._Single
_ = False
1374 if self
._Level
_ > 1:
1375 for Key
in self
.data
:
1376 self
.data
[Key
].SetGreedyMode()
1378 def SetSingleMode(self
):
1379 self
._Single
_ = True
1380 if self
._Level
_ > 1:
1381 for Key
in self
.data
:
1382 self
.data
[Key
].SetSingleMode()
1384 def GetKeys(self
, KeyIndex
=0):
1385 assert KeyIndex
>= 0
1387 return set(self
.data
.keys())
1390 for Key
in self
.data
:
1391 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1394 ## Boolean chain list
1396 class Blist(UserList
):
1397 def __init__(self
, initlist
=None):
1398 UserList
.__init
__(self
, initlist
)
1399 def __setitem__(self
, i
, item
):
1400 if item
not in [True, False]:
1406 def _GetResult(self
):
1408 for item
in self
.data
:
1411 Result
= property(_GetResult
)
1413 def ParseConsoleLog(Filename
):
1414 Opr
= open(os
.path
.normpath(Filename
), 'r')
1415 Opw
= open(os
.path
.normpath(Filename
+ '.New'), 'w+')
1416 for Line
in Opr
.readlines():
1417 if Line
.find('.efi') > -1:
1418 Line
= Line
[Line
.rfind(' ') : Line
.rfind('.efi')].strip()
1419 Opw
.write('%s\n' % Line
)
1424 def AnalyzePcdExpression(Setting
):
1425 Setting
= Setting
.strip()
1426 # There might be escaped quote in a string: \", \\\"
1427 Data
= Setting
.replace('\\\\', '//').replace('\\\"', '\\\'')
1428 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1435 elif ch
== '(' and not InStr
:
1437 elif ch
== ')' and not InStr
:
1440 if (Pair
> 0 or InStr
) and ch
== TAB_VALUE_SPLIT
:
1447 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1449 FieldList
.append(Setting
[StartPos
:].strip())
1451 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1458 # Analyze DSC PCD value, since there is no data type info in DSC
1459 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1460 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1461 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1462 # 3. Dynamic default:
1463 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1464 # TokenSpace.PcdCName|PcdValue
1466 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1467 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1469 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1470 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1471 # there might have "|" operator, also in string value.
1473 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1474 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1475 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1477 # ValueList: A List contain fields described above
1478 # IsValid: True if conforming EBNF, otherwise False
1479 # Index: The index where PcdValue is in ValueList
1481 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1482 FieldList
= AnalyzePcdExpression(Setting
)
1485 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1486 Value
= FieldList
[0]
1488 if len(FieldList
) > 1:
1490 # Fix the PCD type when no DataType input
1495 if len(FieldList
) > 2:
1497 if DataType
== 'VOID*':
1498 IsValid
= (len(FieldList
) <= 3)
1500 IsValid
= (len(FieldList
) <= 1)
1501 return [Value
, '', Size
], IsValid
, 0
1502 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1503 Value
= FieldList
[0]
1505 if len(FieldList
) > 1:
1509 if len(FieldList
) > 2:
1513 if Value
.startswith("L"):
1514 Size
= str((len(Value
)- 3 + 1) * 2)
1515 elif Value
.startswith("{"):
1516 Size
= str(len(Value
.split(",")))
1518 Size
= str(len(Value
) -2 + 1 )
1519 if DataType
== 'VOID*':
1520 IsValid
= (len(FieldList
) <= 3)
1522 IsValid
= (len(FieldList
) <= 1)
1523 return [Value
, Type
, Size
], IsValid
, 0
1524 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1525 VpdOffset
= FieldList
[0]
1527 if not DataType
== 'VOID*':
1528 if len(FieldList
) > 1:
1529 Value
= FieldList
[1]
1531 if len(FieldList
) > 1:
1533 if len(FieldList
) > 2:
1534 Value
= FieldList
[2]
1535 if DataType
== 'VOID*':
1536 IsValid
= (len(FieldList
) <= 3)
1538 IsValid
= (len(FieldList
) <= 2)
1539 return [VpdOffset
, Size
, Value
], IsValid
, 2
1540 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1541 HiiString
= FieldList
[0]
1542 Guid
= Offset
= Value
= Attribute
= ''
1543 if len(FieldList
) > 1:
1545 if len(FieldList
) > 2:
1546 Offset
= FieldList
[2]
1547 if len(FieldList
) > 3:
1548 Value
= FieldList
[3]
1549 if len(FieldList
) > 4:
1550 Attribute
= FieldList
[4]
1551 IsValid
= (3 <= len(FieldList
) <= 5)
1552 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1557 # Analyze the pcd Value, Datum type and TokenNumber.
1558 # Used to avoid split issue while the value string contain "|" character
1560 # @param[in] Setting: A String contain value/datum type/token number information;
1562 # @retval ValueList: A List contain value, datum type and toke number.
1564 def AnalyzePcdData(Setting
):
1565 ValueList
= ['', '', '']
1567 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1568 PtrValue
= ValueRe
.findall(Setting
)
1570 ValueUpdateFlag
= False
1572 if len(PtrValue
) >= 1:
1573 Setting
= re
.sub(ValueRe
, '', Setting
)
1574 ValueUpdateFlag
= True
1576 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1577 ValueList
[0:len(TokenList
)] = TokenList
1580 ValueList
[0] = PtrValue
[0]
1584 ## AnalyzeHiiPcdData
1586 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1587 # Used to avoid split issue while the value string contain "|" character
1589 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1591 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1593 def AnalyzeHiiPcdData(Setting
):
1594 ValueList
= ['', '', '', '']
1596 TokenList
= GetSplitValueList(Setting
)
1597 ValueList
[0:len(TokenList
)] = TokenList
1601 ## AnalyzeVpdPcdData
1603 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1604 # Used to avoid split issue while the value string contain "|" character
1606 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1608 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1610 def AnalyzeVpdPcdData(Setting
):
1611 ValueList
= ['', '', '']
1613 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1614 PtrValue
= ValueRe
.findall(Setting
)
1616 ValueUpdateFlag
= False
1618 if len(PtrValue
) >= 1:
1619 Setting
= re
.sub(ValueRe
, '', Setting
)
1620 ValueUpdateFlag
= True
1622 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1623 ValueList
[0:len(TokenList
)] = TokenList
1626 ValueList
[2] = PtrValue
[0]
1630 ## check format of PCD value against its the datum type
1632 # For PCD value setting
1634 def CheckPcdDatum(Type
, Value
):
1636 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1637 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1638 or (Value
.startswith('{') and Value
.endswith('}'))
1640 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1641 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1642 elif ValueRe
.match(Value
):
1643 # Check the chars in UnicodeString or CString is printable
1644 if Value
.startswith("L"):
1648 Printset
= set(string
.printable
)
1649 Printset
.remove(TAB_PRINTCHAR_VT
)
1650 Printset
.add(TAB_PRINTCHAR_BS
)
1651 Printset
.add(TAB_PRINTCHAR_NUL
)
1652 if not set(Value
).issubset(Printset
):
1653 PrintList
= list(Printset
)
1655 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1656 elif Type
== 'BOOLEAN':
1657 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1658 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1659 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1660 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1662 Value
= long(Value
, 0)
1664 return False, "Invalid value [%s] of type [%s];"\
1665 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1667 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type
)
1671 ## Split command line option string to list
1673 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1674 # in non-windows platform to launch command
1676 def SplitOption(OptionString
):
1681 for Index
in range(0, len(OptionString
)):
1682 CurrentChar
= OptionString
[Index
]
1683 if CurrentChar
in ['"', "'"]:
1684 if QuotationMark
== CurrentChar
:
1686 elif QuotationMark
== "":
1687 QuotationMark
= CurrentChar
1692 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1693 if Index
> OptionStart
:
1694 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1696 LastChar
= CurrentChar
1697 OptionList
.append(OptionString
[OptionStart
:])
1700 def CommonPath(PathList
):
1701 P1
= min(PathList
).split(os
.path
.sep
)
1702 P2
= max(PathList
).split(os
.path
.sep
)
1703 for Index
in xrange(min(len(P1
), len(P2
))):
1704 if P1
[Index
] != P2
[Index
]:
1705 return os
.path
.sep
.join(P1
[:Index
])
1706 return os
.path
.sep
.join(P1
)
1709 # Convert string to C format array
1711 def ConvertStringToByteArray(Value
):
1712 Value
= Value
.strip()
1716 if not Value
.endswith('}'):
1718 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1719 ValFields
= Value
.split(',')
1721 for Index
in range(len(ValFields
)):
1722 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1725 Value
= '{' + ','.join(ValFields
) + '}'
1729 if Value
.startswith('L"'):
1730 if not Value
.endswith('"'):
1734 elif not Value
.startswith('"') or not Value
.endswith('"'):
1737 Value
= eval(Value
) # translate escape character
1739 for Index
in range(0,len(Value
)):
1741 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1743 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1744 Value
= NewValue
+ '0}'
1747 class PathClass(object):
1748 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1749 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1751 self
.File
= str(File
)
1752 if os
.path
.isabs(self
.File
):
1756 self
.Root
= str(Root
)
1757 self
.AlterRoot
= str(AlterRoot
)
1759 # Remove any '.' and '..' in path
1761 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1762 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1763 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1764 # eliminate the side-effect of 'C:'
1765 if self
.Root
[-1] == ':':
1766 self
.Root
+= os
.path
.sep
1767 # file path should not start with path separator
1768 if self
.Root
[-1] == os
.path
.sep
:
1769 self
.File
= self
.Path
[len(self
.Root
):]
1771 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1773 self
.Path
= os
.path
.normpath(self
.File
)
1775 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1776 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1780 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1782 self
.Dir
= self
.Root
1784 self
.Dir
= self
.SubDir
1789 self
.Type
= self
.Ext
.lower()
1791 self
.IsBinary
= IsBinary
1792 self
.Target
= Target
1793 self
.TagName
= TagName
1794 self
.ToolCode
= ToolCode
1795 self
.ToolChainFamily
= ToolChainFamily
1799 ## Convert the object of this class to a string
1801 # Convert member Path of the class to a string
1803 # @retval string Formatted String
1808 ## Override __eq__ function
1810 # Check whether PathClass are the same
1812 # @retval False The two PathClass are different
1813 # @retval True The two PathClass are the same
1815 def __eq__(self
, Other
):
1816 if type(Other
) == type(self
):
1817 return self
.Path
== Other
.Path
1819 return self
.Path
== str(Other
)
1821 ## Override __cmp__ function
1823 # Customize the comparsion operation of two PathClass
1825 # @retval 0 The two PathClass are different
1826 # @retval -1 The first PathClass is less than the second PathClass
1827 # @retval 1 The first PathClass is Bigger than the second PathClass
1828 def __cmp__(self
, Other
):
1829 if type(Other
) == type(self
):
1830 OtherKey
= Other
.Path
1832 OtherKey
= str(Other
)
1835 if SelfKey
== OtherKey
:
1837 elif SelfKey
> OtherKey
:
1842 ## Override __hash__ function
1844 # Use Path as key in hash table
1846 # @retval string Key for hash table
1849 return hash(self
.Path
)
1851 def _GetFileKey(self
):
1852 if self
._Key
== None:
1853 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1856 def _GetTimeStamp(self
):
1857 return os
.stat(self
.Path
)[8]
1859 def Validate(self
, Type
='', CaseSensitive
=True):
1860 if GlobalData
.gCaseInsensitive
:
1861 CaseSensitive
= False
1862 if Type
and Type
.lower() != self
.Type
:
1863 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1865 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1866 if not RealRoot
and not RealFile
:
1867 RealFile
= self
.File
1869 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1871 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1872 if len (mws
.getPkgPath()) == 0:
1873 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1875 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1879 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1880 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1881 ErrorCode
= FILE_CASE_MISMATCH
1882 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1884 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1885 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1887 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1890 self
.File
= RealFile
1891 self
.Root
= RealRoot
1892 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1893 return ErrorCode
, ErrorInfo
1895 Key
= property(_GetFileKey
)
1896 TimeStamp
= property(_GetTimeStamp
)
1898 ## Parse PE image to get the required PE informaion.
1900 class PeImageClass():
1903 # @param File FilePath of PeImage
1905 def __init__(self
, PeFile
):
1906 self
.FileName
= PeFile
1907 self
.IsValid
= False
1910 self
.SectionAlignment
= 0
1911 self
.SectionHeaderList
= []
1914 PeObject
= open(PeFile
, 'rb')
1916 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1919 ByteArray
= array
.array('B')
1920 ByteArray
.fromfile(PeObject
, 0x3E)
1921 ByteList
= ByteArray
.tolist()
1922 # DOS signature should be 'MZ'
1923 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1924 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1927 # Read 4 byte PE Signature
1928 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1929 PeObject
.seek(PeOffset
)
1930 ByteArray
= array
.array('B')
1931 ByteArray
.fromfile(PeObject
, 4)
1932 # PE signature should be 'PE\0\0'
1933 if ByteArray
.tostring() != 'PE\0\0':
1934 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1937 # Read PE file header
1938 ByteArray
= array
.array('B')
1939 ByteArray
.fromfile(PeObject
, 0x14)
1940 ByteList
= ByteArray
.tolist()
1941 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1943 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1946 # Read PE optional header
1947 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1948 ByteArray
= array
.array('B')
1949 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1950 ByteList
= ByteArray
.tolist()
1951 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1952 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1953 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1955 # Read each Section Header
1956 for Index
in range(SecNumber
):
1957 ByteArray
= array
.array('B')
1958 ByteArray
.fromfile(PeObject
, 0x28)
1959 ByteList
= ByteArray
.tolist()
1960 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1961 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1962 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1963 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1964 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1968 def _ByteListToStr(self
, ByteList
):
1970 for index
in range(len(ByteList
)):
1971 if ByteList
[index
] == 0:
1973 String
+= chr(ByteList
[index
])
1976 def _ByteListToInt(self
, ByteList
):
1978 for index
in range(len(ByteList
) - 1, -1, -1):
1979 Value
= (Value
<< 8) |
int(ByteList
[index
])
1989 def __init__(self
,SkuIdentifier
='', SkuIds
={}):
1991 self
.AvailableSkuIds
= sdict()
1993 self
.SkuIdNumberSet
= []
1994 if SkuIdentifier
== '' or SkuIdentifier
is None:
1995 self
.SkuIdSet
= ['DEFAULT']
1996 self
.SkuIdNumberSet
= ['0U']
1997 elif SkuIdentifier
== 'ALL':
1998 self
.SkuIdSet
= SkuIds
.keys()
1999 self
.SkuIdNumberSet
= [num
.strip() + 'U' for num
in SkuIds
.values()]
2001 r
= SkuIdentifier
.split('|')
2002 self
.SkuIdSet
=[r
[k
].strip() for k
in range(len(r
))]
2005 self
.SkuIdNumberSet
= [SkuIds
[k
].strip() + 'U' for k
in self
.SkuIdSet
]
2007 EdkLogger
.error("build", PARAMETER_INVALID
,
2008 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
2009 % (k
, " | ".join(SkuIds
.keys())))
2010 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
and SkuIdentifier
!= 'ALL':
2011 self
.SkuIdSet
.remove('DEFAULT')
2012 self
.SkuIdNumberSet
.remove('0U')
2013 for each
in self
.SkuIdSet
:
2015 self
.AvailableSkuIds
[each
] = SkuIds
[each
]
2017 EdkLogger
.error("build", PARAMETER_INVALID
,
2018 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
2019 % (each
, " | ".join(SkuIds
.keys())))
2021 def __SkuUsageType(self
):
2023 if len(self
.SkuIdSet
) == 1:
2024 if self
.SkuIdSet
[0] == 'DEFAULT':
2025 return SkuClass
.DEFAULT
2027 return SkuClass
.SINGLE
2029 return SkuClass
.MULTIPLE
2031 def __GetAvailableSkuIds(self
):
2032 return self
.AvailableSkuIds
2034 def __GetSystemSkuID(self
):
2035 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2036 return self
.SkuIdSet
[0]
2039 def __GetAvailableSkuIdNumber(self
):
2040 return self
.SkuIdNumberSet
2041 SystemSkuId
= property(__GetSystemSkuID
)
2042 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2043 SkuUsageType
= property(__SkuUsageType
)
2044 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2047 # Pack a registry format GUID
2049 def PackRegistryFormatGuid(Guid
):
2050 Guid
= Guid
.split('-')
2051 return pack('=LHHBBBBBBBB',
2055 int(Guid
[3][-4:-2], 16),
2056 int(Guid
[3][-2:], 16),
2057 int(Guid
[4][-12:-10], 16),
2058 int(Guid
[4][-10:-8], 16),
2059 int(Guid
[4][-8:-6], 16),
2060 int(Guid
[4][-6:-4], 16),
2061 int(Guid
[4][-4:-2], 16),
2062 int(Guid
[4][-2:], 16)
2065 def BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, Value
):
2066 if PcdDatumType
== 'VOID*':
2067 if Value
.startswith('L'):
2069 EdkLogger
.error("build", FORMAT_INVALID
, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"')
2070 Value
= Value
[0] + '"' + Value
[1:] + '"'
2071 elif Value
.startswith('H'):
2073 EdkLogger
.error("build", FORMAT_INVALID
, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"')
2077 EdkLogger
.error("build", FORMAT_INVALID
, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"')
2078 Value
= '"' + Value
+ '"'
2080 IsValid
, Cause
= CheckPcdDatum(PcdDatumType
, Value
)
2082 EdkLogger
.error("build", FORMAT_INVALID
, Cause
, ExtraData
="%s.%s" % (TokenSpaceGuidCName
, TokenCName
))
2083 if PcdDatumType
== 'BOOLEAN':
2084 Value
= Value
.upper()
2085 if Value
== 'TRUE' or Value
== '1':
2087 elif Value
== 'FALSE' or Value
== '0':
2093 # This acts like the main() function for the script, unless it is 'import'ed into another
2096 if __name__
== '__main__':