2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2019, 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 from __future__
import absolute_import
27 from random
import sample
28 from struct
import pack
31 from collections
import OrderedDict
33 import Common
.LongFilePathOs
as os
34 from Common
import EdkLogger
as EdkLogger
35 from Common
import GlobalData
as GlobalData
36 from Common
.DataType
import *
37 from Common
.BuildToolError
import *
38 from CommonDataClass
.DataClass
import *
39 from Common
.Parsing
import GetSplitValueList
40 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
41 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
42 from CommonDataClass
.Exceptions
import BadExpression
43 from Common
.caching
import cached_property
45 ## Regular expression used to find out place holders in string template
46 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE | re
.UNICODE
)
48 ## regular expressions for map file processing
49 startPatternGeneral
= re
.compile("^Start[' ']+Length[' ']+Name[' ']+Class")
50 addressPatternGeneral
= re
.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")
51 valuePatternGcc
= re
.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')
52 pcdPatternGcc
= re
.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')
53 secReGeneral
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
55 StructPattern
= re
.compile(r
'[_a-zA-Z][0-9A-Za-z_]*$')
57 ## Dictionary used to store dependencies of files
58 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
61 # If a module is built more than once with different PCDs or library classes
62 # a temporary INF file with same content is created, the temporary file is removed
67 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
68 """ Parse map file to get variable offset in current EFI file
69 @param mapfilepath Map file absolution path
70 @param efifilepath: EFI binary file full path
71 @param varnames iteratable container whose elements are variable names to be searched
73 @return List whos elements are tuple with variable name and raw offset
77 f
= open(mapfilepath
, 'r')
83 if len(lines
) == 0: return None
84 firstline
= lines
[0].strip()
85 if (firstline
.startswith("Archive member included ") and
86 firstline
.endswith(" file (symbol)")):
87 return _parseForGCC(lines
, efifilepath
, varnames
)
88 if firstline
.startswith("# Path:"):
89 return _parseForXcode(lines
, efifilepath
, varnames
)
90 return _parseGeneral(lines
, efifilepath
, varnames
)
92 def _parseForXcode(lines
, efifilepath
, varnames
):
97 if status
== 0 and line
== "# Symbols:":
100 if status
== 1 and len(line
) != 0:
101 for varname
in varnames
:
103 # cannot pregenerate this RegEx since it uses varname from varnames.
104 m
= re
.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname
, line
)
106 ret
.append((varname
, m
.group(1)))
109 def _parseForGCC(lines
, efifilepath
, varnames
):
110 """ Parse map file generated by GCC linker """
114 for index
, line
in enumerate(lines
):
116 # status machine transection
117 if status
== 0 and line
== "Memory Configuration":
120 elif status
== 1 and line
== 'Linker script and memory map':
123 elif status
==2 and line
== 'START GROUP':
129 m
= valuePatternGcc
.match(line
)
131 sections
.append(m
.groups(0))
132 for varname
in varnames
:
134 m
= re
.match("^.data.(%s)" % varname
, line
)
136 m
= re
.match(".data.(%s)$" % varname
, line
)
138 Str
= lines
[index
+ 1]
140 Str
= line
[len(".data.%s" % varname
):]
142 m
= pcdPatternGcc
.match(Str
.strip())
144 varoffset
.append((varname
, int(m
.groups(0)[0], 16), int(sections
[-1][1], 16), sections
[-1][0]))
148 # get section information from efi file
149 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
150 if efisecs
is None or len(efisecs
) == 0:
154 for efisec
in efisecs
:
155 for section
in sections
:
156 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
157 redirection
= int(section
[1], 16) - efisec
[1]
160 for var
in varoffset
:
161 for efisec
in efisecs
:
162 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
163 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
166 def _parseGeneral(lines
, efifilepath
, varnames
):
167 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
168 secs
= [] # key = section name
170 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
174 if startPatternGeneral
.match(line
):
177 if addressPatternGeneral
.match(line
):
180 if line
.startswith("entry point at"):
183 if status
== 1 and len(line
) != 0:
184 m
= secReGeneral
.match(line
)
185 assert m
is not None, "Fail to parse the section in map file , line is %s" % line
186 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
187 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
188 if status
== 2 and len(line
) != 0:
189 for varname
in varnames
:
190 m
= symRe
.match(line
)
191 assert m
is not None, "Fail to parse the symbol in map file, line is %s" % line
192 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
193 sec_no
= int(sec_no
, 16)
194 sym_offset
= int(sym_offset
, 16)
195 vir_addr
= int(vir_addr
, 16)
196 # cannot pregenerate this RegEx since it uses varname from varnames.
197 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
199 # fond a binary pcd entry in map file
201 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
202 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
204 if not varoffset
: return []
206 # get section information from efi file
207 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
208 if efisecs
is None or len(efisecs
) == 0:
212 for var
in varoffset
:
214 for efisec
in efisecs
:
216 if var
[1].strip() == efisec
[0].strip():
217 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
218 elif var
[4] == index
:
219 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
223 ## Routine to process duplicated INF
225 # This function is called by following two cases:
228 # Pkg/module/module.inf
229 # Pkg/module/module.inf {
231 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
234 # INF Pkg/module/module.inf
235 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
237 # This function copies Pkg/module/module.inf to
238 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
240 # @param Path Original PathClass object
241 # @param BaseName New file base name
243 # @retval return the new PathClass object
245 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
246 Filename
= os
.path
.split(Path
.File
)[1]
248 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
250 Filename
= BaseName
+ Path
.BaseName
253 # If -N is specified on command line, cache is disabled
254 # The directory has to be created
256 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
257 if not os
.path
.exists(DbDir
):
260 # A temporary INF is copied to database path which must have write permission
261 # The temporary will be removed at the end of build
262 # In case of name conflict, the file name is
263 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
265 TempFullPath
= os
.path
.join(DbDir
,
267 RtPath
= PathClass(Path
.File
, Workspace
)
269 # Modify the full path to temporary path, keep other unchanged
271 # To build same module more than once, the module path with FILE_GUID overridden has
272 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
273 # in DSC which is used as relative path by C files and other files in INF.
274 # A trick was used: all module paths are PathClass instances, after the initialization
275 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
277 # The reason for creating a temporary INF is:
278 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
279 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
280 # A different key for the same module is needed to create different output directory,
281 # retrieve overridden PCDs, library instances.
283 # The BaseName is the FILE_GUID which is also the output directory name.
286 RtPath
.Path
= TempFullPath
287 RtPath
.BaseName
= BaseName
289 # If file exists, compare contents
291 if os
.path
.exists(TempFullPath
):
292 with
open(str(Path
), 'rb') as f1
, open(TempFullPath
, 'rb') as f2
:
293 if f1
.read() == f2
.read():
295 _TempInfs
.append(TempFullPath
)
296 shutil
.copy2(str(Path
), TempFullPath
)
299 ## Remove temporary created INFs whose paths were saved in _TempInfs
301 def ClearDuplicatedInf():
303 File
= _TempInfs
.pop()
304 if os
.path
.exists(File
):
307 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
309 # @param Guid The GUID string
311 # @retval string The GUID string in C structure style
313 def GuidStringToGuidStructureString(Guid
):
314 GuidList
= Guid
.split('-')
316 for Index
in range(0, 3, 1):
317 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
318 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
319 for Index
in range(0, 12, 2):
320 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
324 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
326 # @param GuidValue The GUID value in byte array
328 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
330 def GuidStructureByteArrayToGuidString(GuidValue
):
331 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
332 guidValueList
= guidValueString
.split(",")
333 if len(guidValueList
) != 16:
335 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
337 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
338 int(guidValueList
[3], 16),
339 int(guidValueList
[2], 16),
340 int(guidValueList
[1], 16),
341 int(guidValueList
[0], 16),
342 int(guidValueList
[5], 16),
343 int(guidValueList
[4], 16),
344 int(guidValueList
[7], 16),
345 int(guidValueList
[6], 16),
346 int(guidValueList
[8], 16),
347 int(guidValueList
[9], 16),
348 int(guidValueList
[10], 16),
349 int(guidValueList
[11], 16),
350 int(guidValueList
[12], 16),
351 int(guidValueList
[13], 16),
352 int(guidValueList
[14], 16),
353 int(guidValueList
[15], 16)
358 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
360 # @param GuidValue The GUID value in C structure format
362 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
364 def GuidStructureStringToGuidString(GuidValue
):
365 if not GlobalData
.gGuidCFormatPattern
.match(GuidValue
):
367 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
368 guidValueList
= guidValueString
.split(",")
369 if len(guidValueList
) != 11:
371 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
373 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
374 int(guidValueList
[0], 16),
375 int(guidValueList
[1], 16),
376 int(guidValueList
[2], 16),
377 int(guidValueList
[3], 16),
378 int(guidValueList
[4], 16),
379 int(guidValueList
[5], 16),
380 int(guidValueList
[6], 16),
381 int(guidValueList
[7], 16),
382 int(guidValueList
[8], 16),
383 int(guidValueList
[9], 16),
384 int(guidValueList
[10], 16)
389 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
391 # @param GuidValue The GUID value in C structure format
393 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
395 def GuidStructureStringToGuidValueName(GuidValue
):
396 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
397 guidValueList
= guidValueString
.split(",")
398 if len(guidValueList
) != 11:
399 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
400 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
401 int(guidValueList
[0], 16),
402 int(guidValueList
[1], 16),
403 int(guidValueList
[2], 16),
404 int(guidValueList
[3], 16),
405 int(guidValueList
[4], 16),
406 int(guidValueList
[5], 16),
407 int(guidValueList
[6], 16),
408 int(guidValueList
[7], 16),
409 int(guidValueList
[8], 16),
410 int(guidValueList
[9], 16),
411 int(guidValueList
[10], 16)
414 ## Create directories
416 # @param Directory The directory name
418 def CreateDirectory(Directory
):
419 if Directory
is None or Directory
.strip() == "":
422 if not os
.access(Directory
, os
.F_OK
):
423 os
.makedirs(Directory
)
428 ## Remove directories, including files and sub-directories in it
430 # @param Directory The directory name
432 def RemoveDirectory(Directory
, Recursively
=False):
433 if Directory
is None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
436 CurrentDirectory
= os
.getcwd()
438 for File
in os
.listdir("."):
439 if os
.path
.isdir(File
):
440 RemoveDirectory(File
, Recursively
)
443 os
.chdir(CurrentDirectory
)
446 ## Store content in file
448 # This method is used to save file only when its content is changed. This is
449 # quite useful for "make" system to decide what will be re-built and what won't.
451 # @param File The path of file
452 # @param Content The new content of the file
453 # @param IsBinaryFile The flag indicating if the file is binary file or not
455 # @retval True If the file content is changed and the file is renewed
456 # @retval False If the file content is the same
458 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
460 Content
= Content
.replace("\n", os
.linesep
)
462 if os
.path
.exists(File
):
464 if Content
== open(File
, "rb").read():
467 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
469 DirName
= os
.path
.dirname(File
)
470 if not CreateDirectory(DirName
):
471 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
474 DirName
= os
.getcwd()
475 if not os
.access(DirName
, os
.W_OK
):
476 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
479 Fd
= open(File
, "wb")
483 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
487 ## Retrieve and cache the real path name in file system
489 # @param Root The root directory of path relative to
491 # @retval str The path string if the path exists
492 # @retval None If path doesn't exist
498 def __init__(self
, Root
):
500 for F
in os
.listdir(Root
):
502 self
._UPPER
_CACHE
_[F
.upper()] = F
505 def __getitem__(self
, Path
):
506 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
509 if Path
and Path
[0] == os
.path
.sep
:
511 if Path
in self
._CACHE
_:
512 return os
.path
.join(self
._Root
, Path
)
513 UpperPath
= Path
.upper()
514 if UpperPath
in self
._UPPER
_CACHE
_:
515 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
519 SepIndex
= Path
.find(os
.path
.sep
)
521 Parent
= UpperPath
[:SepIndex
]
522 if Parent
not in self
._UPPER
_CACHE
_:
524 LastSepIndex
= SepIndex
525 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
527 if LastSepIndex
== -1:
532 SepIndex
= LastSepIndex
534 Parent
= Path
[:SepIndex
]
535 ParentKey
= UpperPath
[:SepIndex
]
536 if ParentKey
not in self
._UPPER
_CACHE
_:
540 if Parent
in self
._CACHE
_:
543 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
544 for F
in os
.listdir(ParentDir
):
545 Dir
= os
.path
.join(ParentDir
, F
)
546 self
._CACHE
_.add(Dir
)
547 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
549 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
552 if Path
in self
._CACHE
_:
553 return os
.path
.join(self
._Root
, Path
)
554 elif UpperPath
in self
._UPPER
_CACHE
_:
555 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
558 def RealPath(File
, Dir
='', OverrideDir
=''):
559 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
560 NewFile
= GlobalData
.gAllFiles
[NewFile
]
561 if not NewFile
and OverrideDir
:
562 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
563 NewFile
= GlobalData
.gAllFiles
[NewFile
]
566 ## Get GUID value from given packages
568 # @param CName The CName of the GUID
569 # @param PackageList List of packages looking-up in
570 # @param Inffile The driver file
572 # @retval GuidValue if the CName is found in any given package
573 # @retval None if the CName is not found in all given packages
575 def GuidValue(CName
, PackageList
, Inffile
= None):
576 for P
in PackageList
:
577 GuidKeys
= list(P
.Guids
.keys())
578 if Inffile
and P
._PrivateGuids
:
579 if not Inffile
.startswith(P
.MetaFile
.Dir
):
580 GuidKeys
= [x
for x
in P
.Guids
if x
not in P
._PrivateGuids
]
581 if CName
in GuidKeys
:
582 return P
.Guids
[CName
]
586 ## A string template class
588 # This class implements a template for string replacement. A string template
589 # looks like following
591 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
593 # The string between ${BEGIN} and ${END} will be repeated as many times as the
594 # length of "placeholder_name", which is a list passed through a dict. The
595 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
596 # be not used and, in this case, the "placeholder_name" must not a list and it
597 # will just be replaced once.
599 class TemplateString(object):
600 _REPEAT_START_FLAG
= "BEGIN"
601 _REPEAT_END_FLAG
= "END"
603 class Section(object):
604 _LIST_TYPES
= [type([]), type(set()), type((0,))]
606 def __init__(self
, TemplateSection
, PlaceHolderList
):
607 self
._Template
= TemplateSection
608 self
._PlaceHolderList
= []
610 # Split the section into sub-sections according to the position of placeholders
612 self
._SubSectionList
= []
615 # The placeholders passed in must be in the format of
617 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
619 for PlaceHolder
, Start
, End
in PlaceHolderList
:
620 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
621 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
622 self
._PlaceHolderList
.append(PlaceHolder
)
623 SubSectionStart
= End
624 if SubSectionStart
< len(TemplateSection
):
625 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
627 self
._SubSectionList
= [TemplateSection
]
630 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
632 def Instantiate(self
, PlaceHolderValues
):
634 RepeatPlaceHolders
= {}
635 NonRepeatPlaceHolders
= {}
637 for PlaceHolder
in self
._PlaceHolderList
:
638 if PlaceHolder
not in PlaceHolderValues
:
640 Value
= PlaceHolderValues
[PlaceHolder
]
641 if type(Value
) in self
._LIST
_TYPES
:
643 RepeatTime
= len(Value
)
644 elif RepeatTime
!= len(Value
):
648 "${%s} has different repeat time from others!" % PlaceHolder
,
649 ExtraData
=str(self
._Template
)
651 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
653 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
655 if NonRepeatPlaceHolders
:
657 for S
in self
._SubSectionList
:
658 if S
not in NonRepeatPlaceHolders
:
661 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
663 StringList
= self
._SubSectionList
665 if RepeatPlaceHolders
:
667 for Index
in range(RepeatTime
):
669 if S
not in RepeatPlaceHolders
:
670 TempStringList
.append(S
)
672 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
673 StringList
= TempStringList
675 return "".join(StringList
)
678 def __init__(self
, Template
=None):
680 self
.IsBinary
= False
681 self
._Template
= Template
682 self
._TemplateSectionList
= self
._Parse
(Template
)
686 # @retval string The string replaced
689 return "".join(self
.String
)
691 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
693 # @retval list A list of TemplateString.Section objects
695 def _Parse(self
, Template
):
700 TemplateSectionList
= []
702 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
704 if MatchEnd
<= len(Template
):
705 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
706 TemplateSectionList
.append(TemplateSection
)
709 MatchString
= MatchObj
.group(1)
710 MatchStart
= MatchObj
.start()
711 MatchEnd
= MatchObj
.end()
713 if MatchString
== self
._REPEAT
_START
_FLAG
:
714 if MatchStart
> SectionStart
:
715 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
716 TemplateSectionList
.append(TemplateSection
)
717 SectionStart
= MatchEnd
719 elif MatchString
== self
._REPEAT
_END
_FLAG
:
720 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
721 TemplateSectionList
.append(TemplateSection
)
722 SectionStart
= MatchEnd
725 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
726 SearchFrom
= MatchEnd
727 return TemplateSectionList
729 ## Replace the string template with dictionary of placeholders and append it to previous one
731 # @param AppendString The string template to append
732 # @param Dictionary The placeholder dictionaries
734 def Append(self
, AppendString
, Dictionary
=None):
736 SectionList
= self
._Parse
(AppendString
)
737 self
.String
.append( "".join(S
.Instantiate(Dictionary
) for S
in SectionList
))
739 if isinstance(AppendString
,list):
740 self
.String
.extend(AppendString
)
742 self
.String
.append(AppendString
)
744 ## Replace the string template with dictionary of placeholders
746 # @param Dictionary The placeholder dictionaries
748 # @retval str The string replaced with placeholder values
750 def Replace(self
, Dictionary
=None):
751 return "".join(S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
)
753 ## Progress indicator class
755 # This class makes use of thread to print progress on console.
758 # for avoiding deadloop
760 _ProgressThread
= None
761 _CheckInterval
= 0.25
765 # @param OpenMessage The string printed before progress charaters
766 # @param CloseMessage The string printed after progress charaters
767 # @param ProgressChar The charater used to indicate the progress
768 # @param Interval The interval in seconds between two progress charaters
770 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
771 self
.PromptMessage
= OpenMessage
772 self
.CodaMessage
= CloseMessage
773 self
.ProgressChar
= ProgressChar
774 self
.Interval
= Interval
775 if Progressor
._StopFlag
is None:
776 Progressor
._StopFlag
= threading
.Event()
778 ## Start to print progress charater
780 # @param OpenMessage The string printed before progress charaters
782 def Start(self
, OpenMessage
=None):
783 if OpenMessage
is not None:
784 self
.PromptMessage
= OpenMessage
785 Progressor
._StopFlag
.clear()
786 if Progressor
._ProgressThread
is None:
787 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
788 Progressor
._ProgressThread
.setDaemon(False)
789 Progressor
._ProgressThread
.start()
791 ## Stop printing progress charater
793 # @param CloseMessage The string printed after progress charaters
795 def Stop(self
, CloseMessage
=None):
796 OriginalCodaMessage
= self
.CodaMessage
797 if CloseMessage
is not None:
798 self
.CodaMessage
= CloseMessage
800 self
.CodaMessage
= OriginalCodaMessage
802 ## Thread entry method
803 def _ProgressThreadEntry(self
):
804 sys
.stdout
.write(self
.PromptMessage
+ " ")
807 while not Progressor
._StopFlag
.isSet():
809 sys
.stdout
.write(self
.ProgressChar
)
811 TimeUp
= self
.Interval
812 time
.sleep(self
._CheckInterval
)
813 TimeUp
-= self
._CheckInterval
814 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
817 ## Abort the progress display
820 if Progressor
._StopFlag
is not None:
821 Progressor
._StopFlag
.set()
822 if Progressor
._ProgressThread
is not None:
823 Progressor
._ProgressThread
.join()
824 Progressor
._ProgressThread
= None
827 ## Dictionary using prioritized list as key
831 _TupleType
= type(())
833 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', TAB_STAR
, 'PLATFORM']
835 def __init__(self
, _Single_
=False, _Level_
=2):
836 self
._Level
_ = _Level_
838 self
._Single
_ = _Single_
841 def __getitem__(self
, key
):
844 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
848 elif self
._Level
_ > 1:
849 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
853 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
855 if FirstKey
is None or str(FirstKey
).upper() in self
._ValidWildcardList
:
856 FirstKey
= self
._Wildcard
859 return self
._GetSingleValue
(FirstKey
, RestKeys
)
861 return self
._GetAllValues
(FirstKey
, RestKeys
)
863 def _GetSingleValue(self
, FirstKey
, RestKeys
):
865 #print "%s-%s" % (FirstKey, self._Level_) ,
867 if FirstKey
== self
._Wildcard
:
868 if FirstKey
in self
.data
:
869 Value
= self
.data
[FirstKey
][RestKeys
]
871 for Key
in self
.data
:
872 Value
= self
.data
[Key
][RestKeys
]
873 if Value
is not None: break
875 if FirstKey
in self
.data
:
876 Value
= self
.data
[FirstKey
][RestKeys
]
877 if Value
is None and self
._Wildcard
in self
.data
:
879 Value
= self
.data
[self
._Wildcard
][RestKeys
]
881 if FirstKey
== self
._Wildcard
:
882 if FirstKey
in self
.data
:
883 Value
= self
.data
[FirstKey
]
885 for Key
in self
.data
:
886 Value
= self
.data
[Key
]
887 if Value
is not None: break
889 if FirstKey
in self
.data
:
890 Value
= self
.data
[FirstKey
]
891 elif self
._Wildcard
in self
.data
:
892 Value
= self
.data
[self
._Wildcard
]
895 def _GetAllValues(self
, FirstKey
, RestKeys
):
898 if FirstKey
== self
._Wildcard
:
899 for Key
in self
.data
:
900 Value
+= self
.data
[Key
][RestKeys
]
902 if FirstKey
in self
.data
:
903 Value
+= self
.data
[FirstKey
][RestKeys
]
904 if self
._Wildcard
in self
.data
:
905 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
907 if FirstKey
== self
._Wildcard
:
908 for Key
in self
.data
:
909 Value
.append(self
.data
[Key
])
911 if FirstKey
in self
.data
:
912 Value
.append(self
.data
[FirstKey
])
913 if self
._Wildcard
in self
.data
:
914 Value
.append(self
.data
[self
._Wildcard
])
918 def __setitem__(self
, key
, value
):
921 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
926 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
930 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
932 if FirstKey
in self
._ValidWildcardList
:
933 FirstKey
= self
._Wildcard
935 if FirstKey
not in self
.data
and self
._Level
_ > 0:
936 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
939 self
.data
[FirstKey
][RestKeys
] = value
941 self
.data
[FirstKey
] = value
943 def SetGreedyMode(self
):
944 self
._Single
_ = False
946 for Key
in self
.data
:
947 self
.data
[Key
].SetGreedyMode()
949 def SetSingleMode(self
):
952 for Key
in self
.data
:
953 self
.data
[Key
].SetSingleMode()
955 def GetKeys(self
, KeyIndex
=0):
958 return set(self
.data
.keys())
961 for Key
in self
.data
:
962 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
965 def AnalyzePcdExpression(Setting
):
966 RanStr
= ''.join(sample(string
.ascii_letters
+ string
.digits
, 8))
967 Setting
= Setting
.replace('\\\\', RanStr
).strip()
968 # There might be escaped quote in a string: \", \\\" , \', \\\'
970 # There might be '|' in string and in ( ... | ... ), replace it with '-'
972 InSingleQuoteStr
= False
973 InDoubleQuoteStr
= False
975 for Index
, ch
in enumerate(Data
):
976 if ch
== '"' and not InSingleQuoteStr
:
977 if Data
[Index
- 1] != '\\':
978 InDoubleQuoteStr
= not InDoubleQuoteStr
979 elif ch
== "'" and not InDoubleQuoteStr
:
980 if Data
[Index
- 1] != '\\':
981 InSingleQuoteStr
= not InSingleQuoteStr
982 elif ch
== '(' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
984 elif ch
== ')' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
987 if (Pair
> 0 or InSingleQuoteStr
or InDoubleQuoteStr
) and ch
== TAB_VALUE_SPLIT
:
994 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
996 FieldList
.append(Setting
[StartPos
:].strip())
998 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1000 for i
, ch
in enumerate(FieldList
):
1002 FieldList
[i
] = ch
.replace(RanStr
,'\\\\')
1005 def ParseFieldValue (Value
):
1006 def ParseDevPathValue (Value
):
1008 Value
.replace('\\', '/').replace(' ', '')
1010 Cmd
= 'DevicePath ' + '"' + Value
+ '"'
1012 p
= subprocess
.Popen(Cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
1013 out
, err
= p
.communicate()
1014 except Exception as X
:
1015 raise BadExpression("DevicePath: %s" % (str(X
)) )
1017 subprocess
._cleanup
()
1021 raise BadExpression("DevicePath: %s" % str(err
))
1022 Size
= len(out
.split())
1023 out
= ','.join(out
.split())
1024 return '{' + out
+ '}', Size
1026 if "{CODE(" in Value
:
1027 return Value
, len(Value
.split(","))
1028 if isinstance(Value
, type(0)):
1029 return Value
, (Value
.bit_length() + 7) // 8
1030 if not isinstance(Value
, type('')):
1031 raise BadExpression('Type %s is %s' %(Value
, type(Value
)))
1032 Value
= Value
.strip()
1033 if Value
.startswith(TAB_UINT8
) and Value
.endswith(')'):
1034 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1036 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1038 if Value
.startswith(TAB_UINT16
) and Value
.endswith(')'):
1039 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1041 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1043 if Value
.startswith(TAB_UINT32
) and Value
.endswith(')'):
1044 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1046 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1048 if Value
.startswith(TAB_UINT64
) and Value
.endswith(')'):
1049 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1051 raise BadExpression('Value (%s) Size larger than %d' % (Value
, Size
))
1053 if Value
.startswith(TAB_GUID
) and Value
.endswith(')'):
1054 Value
= Value
.split('(', 1)[1][:-1].strip()
1055 if Value
[0] == '{' and Value
[-1] == '}':
1056 TmpValue
= GuidStructureStringToGuidString(Value
)
1058 raise BadExpression("Invalid GUID value string %s" % Value
)
1060 if Value
[0] == '"' and Value
[-1] == '"':
1063 Value
= "'" + uuid
.UUID(Value
).bytes_le
+ "'"
1064 except ValueError as Message
:
1065 raise BadExpression(Message
)
1066 Value
, Size
= ParseFieldValue(Value
)
1068 if Value
.startswith('L"') and Value
.endswith('"'):
1070 # translate escape character
1080 Value
= (Value
<< 16) |
ord(Char
)
1081 return Value
, (len(List
) + 1) * 2
1082 if Value
.startswith('"') and Value
.endswith('"'):
1084 # translate escape character
1093 Value
= (Value
<< 8) |
ord(Char
)
1094 return Value
, len(List
) + 1
1095 if Value
.startswith("L'") and Value
.endswith("'"):
1096 # Unicode Character Constant
1097 # translate escape character
1105 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1109 Value
= (Value
<< 16) |
ord(Char
)
1110 return Value
, len(List
) * 2
1111 if Value
.startswith("'") and Value
.endswith("'"):
1112 # Character constant
1113 # translate escape character
1120 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1124 Value
= (Value
<< 8) |
ord(Char
)
1125 return Value
, len(List
)
1126 if Value
.startswith('{') and Value
.endswith('}'):
1129 List
= [Item
.strip() for Item
in Value
.split(',')]
1134 ItemValue
, Size
= ParseFieldValue(Item
)
1136 for I
in range(Size
):
1137 Value
= (Value
<< 8) |
((ItemValue
>> 8 * I
) & 0xff)
1138 return Value
, RetSize
1139 if Value
.startswith('DEVICE_PATH(') and Value
.endswith(')'):
1140 Value
= Value
.replace("DEVICE_PATH(", '').rstrip(')')
1141 Value
= Value
.strip().strip('"')
1142 return ParseDevPathValue(Value
)
1143 if Value
.lower().startswith('0x'):
1145 Value
= int(Value
, 16)
1147 raise BadExpression("invalid hex value: %s" % Value
)
1150 return Value
, (Value
.bit_length() + 7) // 8
1151 if Value
[0].isdigit():
1152 Value
= int(Value
, 10)
1155 return Value
, (Value
.bit_length() + 7) // 8
1156 if Value
.lower() == 'true':
1158 if Value
.lower() == 'false':
1164 # Analyze DSC PCD value, since there is no data type info in DSC
1165 # This function is used to match functions (AnalyzePcdData) used for retrieving PCD value from database
1166 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1167 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1168 # 3. Dynamic default:
1169 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1170 # TokenSpace.PcdCName|PcdValue
1172 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1173 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1175 # TokenSpace.PcdCName|HiiString|VariableGuid|VariableOffset[|HiiValue]
1176 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1177 # there might have "|" operator, also in string value.
1179 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1180 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1181 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1183 # ValueList: A List contain fields described above
1184 # IsValid: True if conforming EBNF, otherwise False
1185 # Index: The index where PcdValue is in ValueList
1187 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1188 FieldList
= AnalyzePcdExpression(Setting
)
1191 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1192 Value
= FieldList
[0]
1194 if len(FieldList
) > 1 and FieldList
[1]:
1195 DataType
= FieldList
[1]
1196 if FieldList
[1] != TAB_VOID
and StructPattern
.match(FieldList
[1]) is None:
1198 if len(FieldList
) > 2:
1202 IsValid
= (len(FieldList
) <= 1)
1204 IsValid
= (len(FieldList
) <= 3)
1208 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1212 return [str(Value
), DataType
, str(Size
)], IsValid
, 0
1213 elif PcdType
== MODEL_PCD_FEATURE_FLAG
:
1214 Value
= FieldList
[0]
1216 IsValid
= (len(FieldList
) <= 1)
1217 return [Value
, DataType
, str(Size
)], IsValid
, 0
1218 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1219 VpdOffset
= FieldList
[0]
1221 if not DataType
== TAB_VOID
:
1222 if len(FieldList
) > 1:
1223 Value
= FieldList
[1]
1225 if len(FieldList
) > 1:
1227 if len(FieldList
) > 2:
1228 Value
= FieldList
[2]
1230 IsValid
= (len(FieldList
) <= 1)
1232 IsValid
= (len(FieldList
) <= 3)
1235 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1239 return [VpdOffset
, str(Size
), Value
], IsValid
, 2
1240 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1241 IsValid
= (3 <= len(FieldList
) <= 5)
1242 HiiString
= FieldList
[0]
1243 Guid
= Offset
= Value
= Attribute
= ''
1244 if len(FieldList
) > 1:
1246 if len(FieldList
) > 2:
1247 Offset
= FieldList
[2]
1248 if len(FieldList
) > 3:
1249 Value
= FieldList
[3]
1250 if len(FieldList
) > 4:
1251 Attribute
= FieldList
[4]
1252 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1257 # Analyze the pcd Value, Datum type and TokenNumber.
1258 # Used to avoid split issue while the value string contain "|" character
1260 # @param[in] Setting: A String contain value/datum type/token number information;
1262 # @retval ValueList: A List contain value, datum type and toke number.
1264 def AnalyzePcdData(Setting
):
1265 ValueList
= ['', '', '']
1267 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1268 PtrValue
= ValueRe
.findall(Setting
)
1270 ValueUpdateFlag
= False
1272 if len(PtrValue
) >= 1:
1273 Setting
= re
.sub(ValueRe
, '', Setting
)
1274 ValueUpdateFlag
= True
1276 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1277 ValueList
[0:len(TokenList
)] = TokenList
1280 ValueList
[0] = PtrValue
[0]
1284 ## check format of PCD value against its the datum type
1286 # For PCD value setting
1288 def CheckPcdDatum(Type
, Value
):
1289 if Type
== TAB_VOID
:
1290 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1291 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1292 or (Value
.startswith('{') and Value
.endswith('}')) or (Value
.startswith("L'") or Value
.startswith("'") and Value
.endswith("'"))
1294 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1295 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value
, Type
)
1296 elif ValueRe
.match(Value
):
1297 # Check the chars in UnicodeString or CString is printable
1298 if Value
.startswith("L"):
1302 Printset
= set(string
.printable
)
1303 Printset
.remove(TAB_PRINTCHAR_VT
)
1304 Printset
.add(TAB_PRINTCHAR_BS
)
1305 Printset
.add(TAB_PRINTCHAR_NUL
)
1306 if not set(Value
).issubset(Printset
):
1307 PrintList
= sorted(Printset
)
1308 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1309 elif Type
== 'BOOLEAN':
1310 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1311 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1312 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1313 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1314 if Value
.startswith('0') and not Value
.lower().startswith('0x') and len(Value
) > 1 and Value
.lstrip('0'):
1315 Value
= Value
.lstrip('0')
1317 if Value
and int(Value
, 0) < 0:
1318 return False, "PCD can't be set to negative value[%s] for datum type [%s]" % (Value
, Type
)
1319 Value
= int(Value
, 0)
1320 if Value
> MAX_VAL_TYPE
[Type
]:
1321 return False, "Too large PCD value[%s] for datum type [%s]" % (Value
, Type
)
1323 return False, "Invalid value [%s] of type [%s];"\
1324 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1326 return True, "StructurePcd"
1330 def CommonPath(PathList
):
1331 P1
= min(PathList
).split(os
.path
.sep
)
1332 P2
= max(PathList
).split(os
.path
.sep
)
1333 for Index
in range(min(len(P1
), len(P2
))):
1334 if P1
[Index
] != P2
[Index
]:
1335 return os
.path
.sep
.join(P1
[:Index
])
1336 return os
.path
.sep
.join(P1
)
1338 class PathClass(object):
1339 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1340 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1342 self
.File
= str(File
)
1343 if os
.path
.isabs(self
.File
):
1347 self
.Root
= str(Root
)
1348 self
.AlterRoot
= str(AlterRoot
)
1350 # Remove any '.' and '..' in path
1352 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1353 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1354 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1355 # eliminate the side-effect of 'C:'
1356 if self
.Root
[-1] == ':':
1357 self
.Root
+= os
.path
.sep
1358 # file path should not start with path separator
1359 if self
.Root
[-1] == os
.path
.sep
:
1360 self
.File
= self
.Path
[len(self
.Root
):]
1362 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1364 self
.Path
= os
.path
.normpath(self
.File
)
1366 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1367 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1371 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1373 self
.Dir
= self
.Root
1375 self
.Dir
= self
.SubDir
1380 self
.Type
= self
.Ext
.lower()
1382 self
.IsBinary
= IsBinary
1383 self
.Target
= Target
1384 self
.TagName
= TagName
1385 self
.ToolCode
= ToolCode
1386 self
.ToolChainFamily
= ToolChainFamily
1388 ## Convert the object of this class to a string
1390 # Convert member Path of the class to a string
1392 # @retval string Formatted String
1397 ## Override __eq__ function
1399 # Check whether PathClass are the same
1401 # @retval False The two PathClass are different
1402 # @retval True The two PathClass are the same
1404 def __eq__(self
, Other
):
1405 return self
.Path
== str(Other
)
1407 ## Override __cmp__ function
1409 # Customize the comparsion operation of two PathClass
1411 # @retval 0 The two PathClass are different
1412 # @retval -1 The first PathClass is less than the second PathClass
1413 # @retval 1 The first PathClass is Bigger than the second PathClass
1414 def __cmp__(self
, Other
):
1415 OtherKey
= str(Other
)
1418 if SelfKey
== OtherKey
:
1420 elif SelfKey
> OtherKey
:
1425 ## Override __hash__ function
1427 # Use Path as key in hash table
1429 # @retval string Key for hash table
1432 return hash(self
.Path
)
1436 return self
.Path
.upper()
1439 def TimeStamp(self
):
1440 return os
.stat(self
.Path
)[8]
1442 def Validate(self
, Type
='', CaseSensitive
=True):
1443 def RealPath2(File
, Dir
='', OverrideDir
=''):
1446 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
1448 if OverrideDir
[-1] == os
.path
.sep
:
1449 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
1451 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
1452 if GlobalData
.gAllFiles
:
1453 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
1455 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
1456 if not os
.path
.exists(NewFile
):
1460 if Dir
[-1] == os
.path
.sep
:
1461 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
1463 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
1469 if GlobalData
.gCaseInsensitive
:
1470 CaseSensitive
= False
1471 if Type
and Type
.lower() != self
.Type
:
1472 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1474 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1475 if not RealRoot
and not RealFile
:
1476 RealFile
= self
.File
1478 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1480 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1481 if len (mws
.getPkgPath()) == 0:
1482 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1484 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1488 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1489 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1490 ErrorCode
= FILE_CASE_MISMATCH
1491 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1493 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1494 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1496 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1499 self
.File
= RealFile
1500 self
.Root
= RealRoot
1501 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1502 return ErrorCode
, ErrorInfo
1504 ## Parse PE image to get the required PE informaion.
1506 class PeImageClass():
1509 # @param File FilePath of PeImage
1511 def __init__(self
, PeFile
):
1512 self
.FileName
= PeFile
1513 self
.IsValid
= False
1516 self
.SectionAlignment
= 0
1517 self
.SectionHeaderList
= []
1520 PeObject
= open(PeFile
, 'rb')
1522 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1525 ByteArray
= array
.array('B')
1526 ByteArray
.fromfile(PeObject
, 0x3E)
1527 ByteList
= ByteArray
.tolist()
1528 # DOS signature should be 'MZ'
1529 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1530 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1533 # Read 4 byte PE Signature
1534 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1535 PeObject
.seek(PeOffset
)
1536 ByteArray
= array
.array('B')
1537 ByteArray
.fromfile(PeObject
, 4)
1538 # PE signature should be 'PE\0\0'
1539 if ByteArray
.tostring() != 'PE\0\0':
1540 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1543 # Read PE file header
1544 ByteArray
= array
.array('B')
1545 ByteArray
.fromfile(PeObject
, 0x14)
1546 ByteList
= ByteArray
.tolist()
1547 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1549 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1552 # Read PE optional header
1553 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1554 ByteArray
= array
.array('B')
1555 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1556 ByteList
= ByteArray
.tolist()
1557 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1558 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1559 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1561 # Read each Section Header
1562 for Index
in range(SecNumber
):
1563 ByteArray
= array
.array('B')
1564 ByteArray
.fromfile(PeObject
, 0x28)
1565 ByteList
= ByteArray
.tolist()
1566 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1567 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1568 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1569 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1570 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1574 def _ByteListToStr(self
, ByteList
):
1576 for index
in range(len(ByteList
)):
1577 if ByteList
[index
] == 0:
1579 String
+= chr(ByteList
[index
])
1582 def _ByteListToInt(self
, ByteList
):
1584 for index
in range(len(ByteList
) - 1, -1, -1):
1585 Value
= (Value
<< 8) |
int(ByteList
[index
])
1588 class DefaultStore():
1589 def __init__(self
, DefaultStores
):
1591 self
.DefaultStores
= DefaultStores
1592 def DefaultStoreID(self
, DefaultStoreName
):
1593 for key
, value
in self
.DefaultStores
.items():
1594 if value
== DefaultStoreName
:
1597 def GetDefaultDefault(self
):
1598 if not self
.DefaultStores
or "0" in self
.DefaultStores
:
1599 return "0", TAB_DEFAULT_STORES_DEFAULT
1601 minvalue
= min(int(value_str
) for value_str
in self
.DefaultStores
)
1602 return (str(minvalue
), self
.DefaultStores
[str(minvalue
)])
1603 def GetMin(self
, DefaultSIdList
):
1604 if not DefaultSIdList
:
1605 return TAB_DEFAULT_STORES_DEFAULT
1606 storeidset
= {storeid
for storeid
, storename
in self
.DefaultStores
.values() if storename
in DefaultSIdList
}
1609 minid
= min(storeidset
)
1610 for sid
, name
in self
.DefaultStores
.values():
1619 def __init__(self
,SkuIdentifier
='', SkuIds
=None):
1623 for SkuName
in SkuIds
:
1624 SkuId
= SkuIds
[SkuName
][0]
1625 skuid_num
= int(SkuId
, 16) if SkuId
.upper().startswith("0X") else int(SkuId
)
1626 if skuid_num
> 0xFFFFFFFFFFFFFFFF:
1627 EdkLogger
.error("build", PARAMETER_INVALID
,
1628 ExtraData
= "SKU-ID [%s] value %s exceeds the max value of UINT64"
1631 self
.AvailableSkuIds
= OrderedDict()
1633 self
.SkuIdNumberSet
= []
1634 self
.SkuData
= SkuIds
1635 self
._SkuInherit
= {}
1636 self
._SkuIdentifier
= SkuIdentifier
1637 if SkuIdentifier
== '' or SkuIdentifier
is None:
1638 self
.SkuIdSet
= ['DEFAULT']
1639 self
.SkuIdNumberSet
= ['0U']
1640 elif SkuIdentifier
== 'ALL':
1641 self
.SkuIdSet
= list(SkuIds
.keys())
1642 self
.SkuIdNumberSet
= [num
[0].strip() + 'U' for num
in SkuIds
.values()]
1644 r
= SkuIdentifier
.split('|')
1645 self
.SkuIdSet
=[(r
[k
].strip()).upper() for k
in range(len(r
))]
1648 self
.SkuIdNumberSet
= [SkuIds
[k
][0].strip() + 'U' for k
in self
.SkuIdSet
]
1650 EdkLogger
.error("build", PARAMETER_INVALID
,
1651 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1652 % (k
, " | ".join(SkuIds
.keys())))
1653 for each
in self
.SkuIdSet
:
1655 self
.AvailableSkuIds
[each
] = SkuIds
[each
][0]
1657 EdkLogger
.error("build", PARAMETER_INVALID
,
1658 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1659 % (each
, " | ".join(SkuIds
.keys())))
1660 if self
.SkuUsageType
!= SkuClass
.SINGLE
:
1661 self
.AvailableSkuIds
.update({'DEFAULT':0, 'COMMON':0})
1663 GlobalData
.gSkuids
= (self
.SkuIdSet
)
1664 if 'COMMON' in GlobalData
.gSkuids
:
1665 GlobalData
.gSkuids
.remove('COMMON')
1666 if self
.SkuUsageType
== self
.SINGLE
:
1667 if len(GlobalData
.gSkuids
) != 1:
1668 if 'DEFAULT' in GlobalData
.gSkuids
:
1669 GlobalData
.gSkuids
.remove('DEFAULT')
1670 if GlobalData
.gSkuids
:
1671 GlobalData
.gSkuids
.sort()
1673 def GetNextSkuId(self
, skuname
):
1674 if not self
._SkuInherit
:
1675 self
._SkuInherit
= {}
1676 for item
in self
.SkuData
.values():
1677 self
._SkuInherit
[item
[1]]=item
[2] if item
[2] else "DEFAULT"
1678 return self
._SkuInherit
.get(skuname
, "DEFAULT")
1680 def GetSkuChain(self
, sku
):
1681 if sku
== "DEFAULT":
1686 nextsku
= self
.GetNextSkuId(nextsku
)
1687 skulist
.append(nextsku
)
1688 if nextsku
== "DEFAULT":
1692 def SkuOverrideOrder(self
):
1694 for skuname
in self
.SkuIdSet
:
1695 skuorderset
.append(self
.GetSkuChain(skuname
))
1698 for index
in range(max(len(item
) for item
in skuorderset
)):
1699 for subset
in skuorderset
:
1700 if index
> len(subset
)-1:
1702 if subset
[index
] in skuorder
:
1704 skuorder
.append(subset
[index
])
1709 def SkuUsageType(self
):
1710 if self
._SkuIdentifier
.upper() == "ALL":
1711 return SkuClass
.MULTIPLE
1713 if len(self
.SkuIdSet
) == 1:
1714 if self
.SkuIdSet
[0] == 'DEFAULT':
1715 return SkuClass
.DEFAULT
1716 return SkuClass
.SINGLE
1717 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
:
1718 return SkuClass
.SINGLE
1719 return SkuClass
.MULTIPLE
1721 def DumpSkuIdArrary(self
):
1722 if self
.SkuUsageType
== SkuClass
.SINGLE
:
1725 for skuname
in self
.AvailableSkuIds
:
1726 if skuname
== "COMMON":
1728 while skuname
!= "DEFAULT":
1729 ArrayStrList
.append(hex(int(self
.AvailableSkuIds
[skuname
])))
1730 skuname
= self
.GetNextSkuId(skuname
)
1731 ArrayStrList
.append("0x0")
1732 return "{{{myList}}}".format(myList
=",".join(ArrayStrList
))
1735 def AvailableSkuIdSet(self
):
1736 return self
.AvailableSkuIds
1739 def SystemSkuId(self
):
1740 if self
.SkuUsageType
== SkuClass
.SINGLE
:
1741 if len(self
.SkuIdSet
) == 1:
1742 return self
.SkuIdSet
[0]
1744 return self
.SkuIdSet
[0] if self
.SkuIdSet
[0] != 'DEFAULT' else self
.SkuIdSet
[1]
1748 ## Get the integer value from string like "14U" or integer like 2
1750 # @param Input The object that may be either a integer value or a string
1752 # @retval Value The integer value that the input represents
1754 def GetIntegerValue(Input
):
1755 if type(Input
) in (int, long):
1758 if String
.endswith("U"):
1759 String
= String
[:-1]
1760 if String
.endswith("ULL"):
1761 String
= String
[:-3]
1762 if String
.endswith("LL"):
1763 String
= String
[:-2]
1765 if String
.startswith("0x") or String
.startswith("0X"):
1766 return int(String
, 16)
1773 # Pack a GUID (registry format) list into a buffer and return it
1776 return pack(PACK_PATTERN_GUID
,
1780 int(Guid
[3][-4:-2], 16),
1781 int(Guid
[3][-2:], 16),
1782 int(Guid
[4][-12:-10], 16),
1783 int(Guid
[4][-10:-8], 16),
1784 int(Guid
[4][-8:-6], 16),
1785 int(Guid
[4][-6:-4], 16),
1786 int(Guid
[4][-4:-2], 16),
1787 int(Guid
[4][-2:], 16)
1791 # Pack a GUID (byte) list into a buffer and return it
1793 def PackByteFormatGUID(Guid
):
1794 return pack(PACK_PATTERN_GUID
,
1808 ## DeepCopy dict/OrderedDict recusively
1810 # @param ori_dict a nested dict or ordereddict
1812 # @retval new dict or orderdict
1814 def CopyDict(ori_dict
):
1815 dict_type
= ori_dict
.__class
__
1816 if dict_type
not in (dict,OrderedDict
):
1818 new_dict
= dict_type()
1819 for key
in ori_dict
:
1820 if isinstance(ori_dict
[key
],(dict,OrderedDict
)):
1821 new_dict
[key
] = CopyDict(ori_dict
[key
])
1823 new_dict
[key
] = ori_dict
[key
]
1827 # Remove the c/c++ comments: // and /* */
1829 def RemoveCComments(ctext
):
1830 return re
.sub('//.*?\n|/\*.*?\*/', '\n', ctext
, flags
=re
.S
)