2 # This file contained the parser for INF file
4 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
6 # This program and the accompanying materials are licensed and made available
7 # under the terms and conditions of the BSD License which accompanies this
8 # distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
24 from copy
import deepcopy
26 from Library
.StringUtils
import GetSplitValueList
27 from Library
.StringUtils
import ConvertSpecialChar
28 from Library
.Misc
import ProcessLineExtender
29 from Library
.Misc
import ProcessEdkComment
30 from Library
.Parsing
import NormPath
31 from Library
.ParserValidate
import IsValidInfMoudleTypeList
32 from Library
.ParserValidate
import IsValidArch
33 from Library
import DataType
as DT
34 from Library
import GlobalData
36 import Logger
.Log
as Logger
37 from Logger
import StringTable
as ST
38 from Logger
.ToolError
import FORMAT_INVALID
39 from Logger
.ToolError
import FILE_READ_FAILURE
40 from Logger
.ToolError
import PARSER_ERROR
42 from Object
.Parser
.InfCommonObject
import InfSectionCommonDef
43 from Parser
.InfSectionParser
import InfSectionParser
44 from Parser
.InfParserMisc
import gINF_SECTION_DEF
45 from Parser
.InfParserMisc
import IsBinaryInf
50 def OpenInfFile(Filename
):
54 FInputfile
= open(Filename
, "rb", 0)
56 FileLinesList
= FInputfile
.readlines()
58 Logger
.Error("InfParser",
60 ST
.ERR_FILE_OPEN_FAILURE
,
65 Logger
.Error("InfParser",
67 ST
.ERR_FILE_OPEN_FAILURE
,
74 # This class defined the structure used in InfParser object
76 # @param InfObject: Inherited from InfSectionParser class
77 # @param Filename: Input value for Filename of INF file, default is
79 # @param WorkspaceDir: Input value for current workspace directory,
82 class InfParser(InfSectionParser
):
84 def __init__(self
, Filename
= None, WorkspaceDir
= None):
87 # Call parent class construct function
89 super(InfParser
, self
).__init
__()
91 self
.WorkspaceDir
= WorkspaceDir
92 self
.SupArchList
= DT
.ARCH_LIST
95 self
.BootModeList
= []
98 # Load Inf file if filename is not None
100 if Filename
is not None:
101 self
.ParseInfFile(Filename
)
105 # Parse the file if it exists
107 # @param Filename: Input value for filename of INF file
109 def ParseInfFile(self
, Filename
):
111 Filename
= NormPath(Filename
)
112 (Path
, Name
) = os
.path
.split(Filename
)
113 self
.FullPath
= Filename
116 GlobalData
.gINF_MODULE_DIR
= Path
117 GlobalData
.gINF_MODULE_NAME
= self
.FullPath
118 GlobalData
.gIS_BINARY_INF
= False
120 # Initialize common data
123 CurrentSection
= DT
.MODEL_UNKNOWN
129 HeaderCommentStart
= False
130 HeaderCommentEnd
= False
131 HeaderStarLineNo
= -1
132 BinaryHeaderCommentStart
= False
133 BinaryHeaderCommentEnd
= False
134 BinaryHeaderStarLineNo
= -1
137 # While Section ends. parse whole section contents.
139 NewSectionStartFlag
= False
140 FirstSectionStartFlag
= False
148 # Variables for Event/Hob/BootMode
152 self
.BootModeList
= []
155 FileLinesList
= OpenInfFile (Filename
)
158 # One INF file can only has one [Defines] section.
160 DefineSectionParsedFlag
= False
163 # Convert special characters in lines to space character.
165 FileLinesList
= ConvertSpecialChar(FileLinesList
)
168 # Process Line Extender
170 FileLinesList
= ProcessLineExtender(FileLinesList
)
173 # Process EdkI INF style comment if found
175 OrigLines
= [Line
for Line
in FileLinesList
]
176 FileLinesList
, EdkCommentStartPos
= ProcessEdkComment(FileLinesList
)
179 # Judge whether the INF file is Binary INF or not
181 if IsBinaryInf(FileLinesList
):
182 GlobalData
.gIS_BINARY_INF
= True
184 InfSectionCommonDefObj
= None
186 for Line
in FileLinesList
:
189 if (LineNo
< len(FileLinesList
) - 1):
190 NextLine
= FileLinesList
[LineNo
].strip()
195 if (Line
== '' or not Line
) and LineNo
== len(FileLinesList
):
196 LastSectionFalg
= True
199 # check whether file header comment section started
201 if Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) and \
202 (Line
.find(DT
.TAB_HEADER_COMMENT
) > -1) and \
203 not HeaderCommentStart
and not HeaderCommentEnd
:
205 CurrentSection
= DT
.MODEL_META_DATA_FILE_HEADER
207 # Append the first line to section lines.
209 HeaderStarLineNo
= LineNo
210 SectionLines
.append((Line
, LineNo
))
211 HeaderCommentStart
= True
215 # Collect Header content.
217 if (Line
.startswith(DT
.TAB_COMMENT_SPLIT
) and CurrentSection
== DT
.MODEL_META_DATA_FILE_HEADER
) and\
218 HeaderCommentStart
and not Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) and not\
219 HeaderCommentEnd
and NextLine
!= '':
220 SectionLines
.append((Line
, LineNo
))
225 if (Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) or not Line
.strip().startswith("#")) and HeaderCommentStart \
226 and not HeaderCommentEnd
:
227 HeaderCommentEnd
= True
228 BinaryHeaderCommentStart
= False
229 BinaryHeaderCommentEnd
= False
230 HeaderCommentStart
= False
231 if Line
.find(DT
.TAB_BINARY_HEADER_COMMENT
) > -1:
232 self
.InfHeaderParser(SectionLines
, self
.InfHeader
, self
.FileName
)
235 SectionLines
.append((Line
, LineNo
))
237 # Call Header comment parser.
239 self
.InfHeaderParser(SectionLines
, self
.InfHeader
, self
.FileName
)
244 # check whether binary header comment section started
246 if Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) and \
247 (Line
.find(DT
.TAB_BINARY_HEADER_COMMENT
) > -1) and \
248 not BinaryHeaderCommentStart
:
250 CurrentSection
= DT
.MODEL_META_DATA_FILE_HEADER
252 # Append the first line to section lines.
254 BinaryHeaderStarLineNo
= LineNo
255 SectionLines
.append((Line
, LineNo
))
256 BinaryHeaderCommentStart
= True
257 HeaderCommentEnd
= True
261 # check whether there are more than one binary header exist
263 if Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) and BinaryHeaderCommentStart
and \
264 not BinaryHeaderCommentEnd
and (Line
.find(DT
.TAB_BINARY_HEADER_COMMENT
) > -1):
265 Logger
.Error('Parser',
267 ST
.ERR_MULTIPLE_BINARYHEADER_EXIST
,
271 # Collect Binary Header content.
273 if (Line
.startswith(DT
.TAB_COMMENT_SPLIT
) and CurrentSection
== DT
.MODEL_META_DATA_FILE_HEADER
) and\
274 BinaryHeaderCommentStart
and not Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) and not\
275 BinaryHeaderCommentEnd
and NextLine
!= '':
276 SectionLines
.append((Line
, LineNo
))
279 # Binary Header content end
281 if (Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) or not Line
.strip().startswith(DT
.TAB_COMMENT_SPLIT
)) and \
282 BinaryHeaderCommentStart
and not BinaryHeaderCommentEnd
:
283 SectionLines
.append((Line
, LineNo
))
284 BinaryHeaderCommentStart
= False
286 # Call Binary Header comment parser.
288 self
.InfHeaderParser(SectionLines
, self
.InfBinaryHeader
, self
.FileName
, True)
290 BinaryHeaderCommentEnd
= True
293 # Find a new section tab
294 # Or at the last line of INF file,
295 # need to process the last section.
297 LastSectionFalg
= False
298 if LineNo
== len(FileLinesList
):
299 LastSectionFalg
= True
301 if Line
.startswith(DT
.TAB_COMMENT_SPLIT
) and not Line
.startswith(DT
.TAB_SPECIAL_COMMENT
):
302 SectionLines
.append((Line
, LineNo
))
303 if not LastSectionFalg
:
307 # Encountered a section. start with '[' and end with ']'
309 if (Line
.startswith(DT
.TAB_SECTION_START
) and \
310 Line
.find(DT
.TAB_SECTION_END
) > -1) or LastSectionFalg
:
312 HeaderCommentEnd
= True
313 BinaryHeaderCommentEnd
= True
315 if not LastSectionFalg
:
317 # check to prevent '#' inside section header
319 HeaderContent
= Line
[1:Line
.find(DT
.TAB_SECTION_END
)]
320 if HeaderContent
.find(DT
.TAB_COMMENT_SPLIT
) != -1:
321 Logger
.Error("InfParser",
323 ST
.ERR_INF_PARSER_DEFINE_SECTION_HEADER_INVALID
,
329 # Keep last time section header content for section parser
332 self
.LastSectionHeaderContent
= deepcopy(self
.SectionHeaderContent
)
335 # TailComments in section define.
338 CommentIndex
= Line
.find(DT
.TAB_COMMENT_SPLIT
)
339 if CommentIndex
> -1:
340 TailComments
= Line
[CommentIndex
:]
341 Line
= Line
[:CommentIndex
]
343 InfSectionCommonDefObj
= InfSectionCommonDef()
344 if TailComments
!= '':
345 InfSectionCommonDefObj
.SetTailComments(TailComments
)
346 if CommentBlock
!= '':
347 InfSectionCommonDefObj
.SetHeaderComments(CommentBlock
)
350 # Call section parser before section header parer to avoid encounter EDKI INF file
352 if CurrentSection
== DT
.MODEL_META_DATA_DEFINE
:
353 DefineSectionParsedFlag
= self
._CallSectionParsers
(CurrentSection
,
354 DefineSectionParsedFlag
, SectionLines
,
355 InfSectionCommonDefObj
, LineNo
)
357 # Compare the new section name with current
359 self
.SectionHeaderParser(Line
, self
.FileName
, LineNo
)
361 self
._CheckSectionHeaders
(Line
, LineNo
)
363 SectionType
= _ConvertSecNameToType(self
.SectionHeaderContent
[0][0])
365 if not FirstSectionStartFlag
:
366 CurrentSection
= SectionType
367 FirstSectionStartFlag
= True
369 NewSectionStartFlag
= True
371 SectionLines
.append((Line
, LineNo
))
375 SectionLines
, CurrentSection
= self
._ProcessLastSection
(SectionLines
, Line
, LineNo
, CurrentSection
)
378 # End of section content collect.
379 # Parser the section content collected previously.
381 if NewSectionStartFlag
or LastSectionFalg
:
382 if CurrentSection
!= DT
.MODEL_META_DATA_DEFINE
or \
383 (LastSectionFalg
and CurrentSection
== DT
.MODEL_META_DATA_DEFINE
):
384 DefineSectionParsedFlag
= self
._CallSectionParsers
(CurrentSection
,
385 DefineSectionParsedFlag
, SectionLines
,
386 InfSectionCommonDefObj
, LineNo
)
388 CurrentSection
= SectionType
390 # Clear section lines
394 if HeaderStarLineNo
== -1:
395 Logger
.Error("InfParser",
397 ST
.ERR_NO_SOURCE_HEADER
,
399 if BinaryHeaderStarLineNo
> -1 and HeaderStarLineNo
> -1 and HeaderStarLineNo
> BinaryHeaderStarLineNo
:
400 Logger
.Error("InfParser",
402 ST
.ERR_BINARY_HEADER_ORDER
,
405 # EDKII INF should not have EDKI style comment
407 if EdkCommentStartPos
!= -1:
408 Logger
.Error("InfParser",
410 ST
.ERR_INF_PARSER_EDKI_COMMENT_IN_EDKII
,
412 Line
=EdkCommentStartPos
+ 1,
413 ExtraData
=OrigLines
[EdkCommentStartPos
])
416 # extract [Event] [Hob] [BootMode] sections
418 self
._ExtractEventHobBootMod
(FileLinesList
)
420 ## _CheckSectionHeaders
423 def _CheckSectionHeaders(self
, Line
, LineNo
):
424 if len(self
.SectionHeaderContent
) == 0:
425 Logger
.Error("InfParser",
427 ST
.ERR_INF_PARSER_DEFINE_SECTION_HEADER_INVALID
,
429 Line
=LineNo
, ExtraData
=Line
)
431 for SectionItem
in self
.SectionHeaderContent
:
434 # Not cover Depex/UserExtension section header
437 if SectionItem
[0].strip().upper() == DT
.TAB_INF_FIXED_PCD
.upper() or \
438 SectionItem
[0].strip().upper() == DT
.TAB_INF_PATCH_PCD
.upper() or \
439 SectionItem
[0].strip().upper() == DT
.TAB_INF_PCD_EX
.upper() or \
440 SectionItem
[0].strip().upper() == DT
.TAB_INF_PCD
.upper() or \
441 SectionItem
[0].strip().upper() == DT
.TAB_INF_FEATURE_PCD
.upper():
442 ArchList
= GetSplitValueList(SectionItem
[1].strip(), ' ')
444 ArchList
= [SectionItem
[1].strip()]
446 for Arch
in ArchList
:
447 if (not IsValidArch(Arch
)) and \
448 (SectionItem
[0].strip().upper() != DT
.TAB_DEPEX
.upper()) and \
449 (SectionItem
[0].strip().upper() != DT
.TAB_USER_EXTENSIONS
.upper()) and \
450 (SectionItem
[0].strip().upper() != DT
.TAB_COMMON_DEFINES
.upper()):
451 Logger
.Error("InfParser",
453 ST
.ERR_INF_PARSER_DEFINE_FROMAT_INVALID
%(SectionItem
[1]),
455 Line
=LineNo
, ExtraData
=Line
)
457 # Check if the ModuleType is valid
459 ChkModSectionList
= ['LIBRARYCLASSES']
460 if (self
.SectionHeaderContent
[0][0].upper() in ChkModSectionList
):
461 if SectionItem
[2].strip().upper():
462 MoudleTypeList
= GetSplitValueList(
463 SectionItem
[2].strip().upper())
464 if (not IsValidInfMoudleTypeList(MoudleTypeList
)):
465 Logger
.Error("InfParser",
467 ST
.ERR_INF_PARSER_DEFINE_FROMAT_INVALID
%(SectionItem
[2]),
468 File
=self
.FullPath
, Line
=LineNo
,
471 ## _CallSectionParsers
474 def _CallSectionParsers(self
, CurrentSection
, DefineSectionParsedFlag
,
475 SectionLines
, InfSectionCommonDefObj
, LineNo
):
476 if CurrentSection
== DT
.MODEL_META_DATA_DEFINE
:
477 if not DefineSectionParsedFlag
:
478 self
.InfDefineParser(SectionLines
,
481 InfSectionCommonDefObj
)
482 DefineSectionParsedFlag
= True
484 Logger
.Error("Parser",
486 ST
.ERR_INF_PARSER_MULTI_DEFINE_SECTION
,
488 RaiseError
= Logger
.IS_RAISE_ERROR
)
490 elif CurrentSection
== DT
.MODEL_META_DATA_BUILD_OPTION
:
491 self
.InfBuildOptionParser(SectionLines
,
492 self
.InfBuildOptionSection
,
495 elif CurrentSection
== DT
.MODEL_EFI_LIBRARY_CLASS
:
496 self
.InfLibraryParser(SectionLines
,
497 self
.InfLibraryClassSection
,
500 elif CurrentSection
== DT
.MODEL_META_DATA_PACKAGE
:
501 self
.InfPackageParser(SectionLines
,
502 self
.InfPackageSection
,
505 # [Pcd] Sections, put it together
507 elif CurrentSection
== DT
.MODEL_PCD_FIXED_AT_BUILD
or \
508 CurrentSection
== DT
.MODEL_PCD_PATCHABLE_IN_MODULE
or \
509 CurrentSection
== DT
.MODEL_PCD_FEATURE_FLAG
or \
510 CurrentSection
== DT
.MODEL_PCD_DYNAMIC_EX
or \
511 CurrentSection
== DT
.MODEL_PCD_DYNAMIC
:
512 self
.InfPcdParser(SectionLines
,
516 elif CurrentSection
== DT
.MODEL_EFI_SOURCE_FILE
:
517 self
.InfSourceParser(SectionLines
,
518 self
.InfSourcesSection
,
521 elif CurrentSection
== DT
.MODEL_META_DATA_USER_EXTENSION
:
522 self
.InfUserExtensionParser(SectionLines
,
523 self
.InfUserExtensionSection
,
526 elif CurrentSection
== DT
.MODEL_EFI_PROTOCOL
:
527 self
.InfProtocolParser(SectionLines
,
528 self
.InfProtocolSection
,
531 elif CurrentSection
== DT
.MODEL_EFI_PPI
:
532 self
.InfPpiParser(SectionLines
,
536 elif CurrentSection
== DT
.MODEL_EFI_GUID
:
537 self
.InfGuidParser(SectionLines
,
541 elif CurrentSection
== DT
.MODEL_EFI_DEPEX
:
542 self
.InfDepexParser(SectionLines
,
543 self
.InfDepexSection
,
546 elif CurrentSection
== DT
.MODEL_EFI_BINARY_FILE
:
547 self
.InfBinaryParser(SectionLines
,
548 self
.InfBinariesSection
,
551 # Unknown section type found, raise error.
554 if len(self
.SectionHeaderContent
) >= 1:
555 Logger
.Error("Parser",
557 ST
.ERR_INF_PARSER_UNKNOWN_SECTION
,
558 File
=self
.FullPath
, Line
=LineNo
,
559 RaiseError
= Logger
.IS_RAISE_ERROR
)
561 Logger
.Error("Parser",
563 ST
.ERR_INF_PARSER_NO_SECTION_ERROR
,
564 File
=self
.FullPath
, Line
=LineNo
,
565 RaiseError
= Logger
.IS_RAISE_ERROR
)
567 return DefineSectionParsedFlag
569 def _ExtractEventHobBootMod(self
, FileLinesList
):
570 SpecialSectionStart
= False
571 CheckLocation
= False
572 GFindSpecialCommentRe
= \
573 re
.compile(r
"""#(?:\s*)\[(.*?)\](?:.*)""", re
.DOTALL
)
574 GFindNewSectionRe2
= \
575 re
.compile(r
"""#?(\s*)\[(.*?)\](.*)""", re
.DOTALL
)
578 for Line
in FileLinesList
:
581 MatchObject
= GFindSpecialCommentRe
.search(Line
)
583 SpecialSectionStart
= True
585 if MatchObject
.group(1).upper().startswith("EVENT"):
586 List
= self
.EventList
587 elif MatchObject
.group(1).upper().startswith("HOB"):
589 elif MatchObject
.group(1).upper().startswith("BOOTMODE"):
590 List
= self
.BootModeList
592 SpecialSectionStart
= False
593 CheckLocation
= False
594 if SpecialSectionStart
:
595 Element
.append([Line
, LineNum
])
599 # if currently in special section, try to detect end of current section
601 MatchObject
= GFindNewSectionRe2
.search(Line
)
602 if SpecialSectionStart
:
604 SpecialSectionStart
= False
605 CheckLocation
= False
608 SpecialSectionStart
= False
612 if not Line
.startswith(DT
.TAB_COMMENT_SPLIT
):
613 Logger
.Warn("Parser",
614 ST
.WARN_SPECIAL_SECTION_LOCATION_WRONG
,
615 File
=self
.FullPath
, Line
=LineNum
)
616 SpecialSectionStart
= False
617 CheckLocation
= False
620 Element
.append([Line
, LineNum
])
624 CheckLocation
= False
626 Logger
.Warn("Parser",
627 ST
.WARN_SPECIAL_SECTION_LOCATION_WRONG
,
628 File
=self
.FullPath
, Line
=LineNum
)
629 CheckLocation
= False
631 if len(self
.BootModeList
) >= 1:
632 self
.InfSpecialCommentParser(self
.BootModeList
,
633 self
.InfSpecialCommentSection
,
635 DT
.TYPE_BOOTMODE_SECTION
)
637 if len(self
.EventList
) >= 1:
638 self
.InfSpecialCommentParser(self
.EventList
,
639 self
.InfSpecialCommentSection
,
641 DT
.TYPE_EVENT_SECTION
)
643 if len(self
.HobList
) >= 1:
644 self
.InfSpecialCommentParser(self
.HobList
,
645 self
.InfSpecialCommentSection
,
648 ## _ProcessLastSection
651 def _ProcessLastSection(self
, SectionLines
, Line
, LineNo
, CurrentSection
):
653 # The last line is a section header. will discard it.
655 if not (Line
.startswith(DT
.TAB_SECTION_START
) and Line
.find(DT
.TAB_SECTION_END
) > -1):
656 SectionLines
.append((Line
, LineNo
))
658 if len(self
.SectionHeaderContent
) >= 1:
659 TemSectionName
= self
.SectionHeaderContent
[0][0].upper()
660 if TemSectionName
.upper() not in gINF_SECTION_DEF
.keys():
661 Logger
.Error("InfParser",
663 ST
.ERR_INF_PARSER_UNKNOWN_SECTION
,
667 RaiseError
= Logger
.IS_RAISE_ERROR
670 CurrentSection
= gINF_SECTION_DEF
[TemSectionName
]
671 self
.LastSectionHeaderContent
= self
.SectionHeaderContent
673 return SectionLines
, CurrentSection
675 ## _ConvertSecNameToType
678 def _ConvertSecNameToType(SectionName
):
680 if SectionName
.upper() not in gINF_SECTION_DEF
.keys():
681 SectionType
= DT
.MODEL_UNKNOWN
683 SectionType
= gINF_SECTION_DEF
[SectionName
.upper()]