2 # This file contained the parser for INF file
4 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
18 from copy
import deepcopy
20 from Library
.StringUtils
import GetSplitValueList
21 from Library
.StringUtils
import ConvertSpecialChar
22 from Library
.Misc
import ProcessLineExtender
23 from Library
.Misc
import ProcessEdkComment
24 from Library
.Parsing
import NormPath
25 from Library
.ParserValidate
import IsValidInfMoudleTypeList
26 from Library
.ParserValidate
import IsValidArch
27 from Library
import DataType
as DT
28 from Library
import GlobalData
30 import Logger
.Log
as Logger
31 from Logger
import StringTable
as ST
32 from Logger
.ToolError
import FORMAT_INVALID
33 from Logger
.ToolError
import FILE_READ_FAILURE
34 from Logger
.ToolError
import PARSER_ERROR
36 from Object
.Parser
.InfCommonObject
import InfSectionCommonDef
37 from Parser
.InfSectionParser
import InfSectionParser
38 from Parser
.InfParserMisc
import gINF_SECTION_DEF
39 from Parser
.InfParserMisc
import IsBinaryInf
44 def OpenInfFile(Filename
):
48 FInputfile
= open(Filename
, "r")
50 FileLinesList
= FInputfile
.readlines()
52 Logger
.Error("InfParser",
54 ST
.ERR_FILE_OPEN_FAILURE
,
59 Logger
.Error("InfParser",
61 ST
.ERR_FILE_OPEN_FAILURE
,
68 # This class defined the structure used in InfParser object
70 # @param InfObject: Inherited from InfSectionParser class
71 # @param Filename: Input value for Filename of INF file, default is
73 # @param WorkspaceDir: Input value for current workspace directory,
76 class InfParser(InfSectionParser
):
78 def __init__(self
, Filename
= None, WorkspaceDir
= None):
81 # Call parent class construct function
83 InfSectionParser
.__init
__()
85 self
.WorkspaceDir
= WorkspaceDir
86 self
.SupArchList
= DT
.ARCH_LIST
89 self
.BootModeList
= []
92 # Load Inf file if filename is not None
94 if Filename
is not None:
95 self
.ParseInfFile(Filename
)
99 # Parse the file if it exists
101 # @param Filename: Input value for filename of INF file
103 def ParseInfFile(self
, Filename
):
105 Filename
= NormPath(Filename
)
106 (Path
, Name
) = os
.path
.split(Filename
)
107 self
.FullPath
= Filename
110 GlobalData
.gINF_MODULE_DIR
= Path
111 GlobalData
.gINF_MODULE_NAME
= self
.FullPath
112 GlobalData
.gIS_BINARY_INF
= False
114 # Initialize common data
117 CurrentSection
= DT
.MODEL_UNKNOWN
123 HeaderCommentStart
= False
124 HeaderCommentEnd
= False
125 HeaderStarLineNo
= -1
126 BinaryHeaderCommentStart
= False
127 BinaryHeaderCommentEnd
= False
128 BinaryHeaderStarLineNo
= -1
131 # While Section ends. parse whole section contents.
133 NewSectionStartFlag
= False
134 FirstSectionStartFlag
= False
142 # Variables for Event/Hob/BootMode
146 self
.BootModeList
= []
149 FileLinesList
= OpenInfFile (Filename
)
152 # One INF file can only has one [Defines] section.
154 DefineSectionParsedFlag
= False
157 # Convert special characters in lines to space character.
159 FileLinesList
= ConvertSpecialChar(FileLinesList
)
162 # Process Line Extender
164 FileLinesList
= ProcessLineExtender(FileLinesList
)
167 # Process EdkI INF style comment if found
169 OrigLines
= [Line
for Line
in FileLinesList
]
170 FileLinesList
, EdkCommentStartPos
= ProcessEdkComment(FileLinesList
)
173 # Judge whether the INF file is Binary INF or not
175 if IsBinaryInf(FileLinesList
):
176 GlobalData
.gIS_BINARY_INF
= True
178 InfSectionCommonDefObj
= None
180 for Line
in FileLinesList
:
183 if (LineNo
< len(FileLinesList
) - 1):
184 NextLine
= FileLinesList
[LineNo
].strip()
189 if (Line
== '' or not Line
) and LineNo
== len(FileLinesList
):
190 LastSectionFalg
= True
193 # check whether file header comment section started
195 if Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) and \
196 (Line
.find(DT
.TAB_HEADER_COMMENT
) > -1) and \
197 not HeaderCommentStart
and not HeaderCommentEnd
:
199 CurrentSection
= DT
.MODEL_META_DATA_FILE_HEADER
201 # Append the first line to section lines.
203 HeaderStarLineNo
= LineNo
204 SectionLines
.append((Line
, LineNo
))
205 HeaderCommentStart
= True
209 # Collect Header content.
211 if (Line
.startswith(DT
.TAB_COMMENT_SPLIT
) and CurrentSection
== DT
.MODEL_META_DATA_FILE_HEADER
) and\
212 HeaderCommentStart
and not Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) and not\
213 HeaderCommentEnd
and NextLine
!= '':
214 SectionLines
.append((Line
, LineNo
))
219 if (Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) or not Line
.strip().startswith("#")) and HeaderCommentStart \
220 and not HeaderCommentEnd
:
221 HeaderCommentEnd
= True
222 BinaryHeaderCommentStart
= False
223 BinaryHeaderCommentEnd
= False
224 HeaderCommentStart
= False
225 if Line
.find(DT
.TAB_BINARY_HEADER_COMMENT
) > -1:
226 self
.InfHeaderParser(SectionLines
, self
.InfHeader
, self
.FileName
)
229 SectionLines
.append((Line
, LineNo
))
231 # Call Header comment parser.
233 self
.InfHeaderParser(SectionLines
, self
.InfHeader
, self
.FileName
)
238 # check whether binary header comment section started
240 if Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) and \
241 (Line
.find(DT
.TAB_BINARY_HEADER_COMMENT
) > -1) and \
242 not BinaryHeaderCommentStart
:
244 CurrentSection
= DT
.MODEL_META_DATA_FILE_HEADER
246 # Append the first line to section lines.
248 BinaryHeaderStarLineNo
= LineNo
249 SectionLines
.append((Line
, LineNo
))
250 BinaryHeaderCommentStart
= True
251 HeaderCommentEnd
= True
255 # check whether there are more than one binary header exist
257 if Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) and BinaryHeaderCommentStart
and \
258 not BinaryHeaderCommentEnd
and (Line
.find(DT
.TAB_BINARY_HEADER_COMMENT
) > -1):
259 Logger
.Error('Parser',
261 ST
.ERR_MULTIPLE_BINARYHEADER_EXIST
,
265 # Collect Binary Header content.
267 if (Line
.startswith(DT
.TAB_COMMENT_SPLIT
) and CurrentSection
== DT
.MODEL_META_DATA_FILE_HEADER
) and\
268 BinaryHeaderCommentStart
and not Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) and not\
269 BinaryHeaderCommentEnd
and NextLine
!= '':
270 SectionLines
.append((Line
, LineNo
))
273 # Binary Header content end
275 if (Line
.startswith(DT
.TAB_SPECIAL_COMMENT
) or not Line
.strip().startswith(DT
.TAB_COMMENT_SPLIT
)) and \
276 BinaryHeaderCommentStart
and not BinaryHeaderCommentEnd
:
277 SectionLines
.append((Line
, LineNo
))
278 BinaryHeaderCommentStart
= False
280 # Call Binary Header comment parser.
282 self
.InfHeaderParser(SectionLines
, self
.InfBinaryHeader
, self
.FileName
, True)
284 BinaryHeaderCommentEnd
= True
287 # Find a new section tab
288 # Or at the last line of INF file,
289 # need to process the last section.
291 LastSectionFalg
= False
292 if LineNo
== len(FileLinesList
):
293 LastSectionFalg
= True
295 if Line
.startswith(DT
.TAB_COMMENT_SPLIT
) and not Line
.startswith(DT
.TAB_SPECIAL_COMMENT
):
296 SectionLines
.append((Line
, LineNo
))
297 if not LastSectionFalg
:
301 # Encountered a section. start with '[' and end with ']'
303 if (Line
.startswith(DT
.TAB_SECTION_START
) and \
304 Line
.find(DT
.TAB_SECTION_END
) > -1) or LastSectionFalg
:
306 HeaderCommentEnd
= True
307 BinaryHeaderCommentEnd
= True
309 if not LastSectionFalg
:
311 # check to prevent '#' inside section header
313 HeaderContent
= Line
[1:Line
.find(DT
.TAB_SECTION_END
)]
314 if HeaderContent
.find(DT
.TAB_COMMENT_SPLIT
) != -1:
315 Logger
.Error("InfParser",
317 ST
.ERR_INF_PARSER_DEFINE_SECTION_HEADER_INVALID
,
323 # Keep last time section header content for section parser
326 self
.LastSectionHeaderContent
= deepcopy(self
.SectionHeaderContent
)
329 # TailComments in section define.
332 CommentIndex
= Line
.find(DT
.TAB_COMMENT_SPLIT
)
333 if CommentIndex
> -1:
334 TailComments
= Line
[CommentIndex
:]
335 Line
= Line
[:CommentIndex
]
337 InfSectionCommonDefObj
= InfSectionCommonDef()
338 if TailComments
!= '':
339 InfSectionCommonDefObj
.SetTailComments(TailComments
)
340 if CommentBlock
!= '':
341 InfSectionCommonDefObj
.SetHeaderComments(CommentBlock
)
344 # Call section parser before section header parer to avoid encounter EDKI INF file
346 if CurrentSection
== DT
.MODEL_META_DATA_DEFINE
:
347 DefineSectionParsedFlag
= self
._CallSectionParsers
(CurrentSection
,
348 DefineSectionParsedFlag
, SectionLines
,
349 InfSectionCommonDefObj
, LineNo
)
351 # Compare the new section name with current
353 self
.SectionHeaderParser(Line
, self
.FileName
, LineNo
)
355 self
._CheckSectionHeaders
(Line
, LineNo
)
357 SectionType
= _ConvertSecNameToType(self
.SectionHeaderContent
[0][0])
359 if not FirstSectionStartFlag
:
360 CurrentSection
= SectionType
361 FirstSectionStartFlag
= True
363 NewSectionStartFlag
= True
365 SectionLines
.append((Line
, LineNo
))
369 SectionLines
, CurrentSection
= self
._ProcessLastSection
(SectionLines
, Line
, LineNo
, CurrentSection
)
372 # End of section content collect.
373 # Parser the section content collected previously.
375 if NewSectionStartFlag
or LastSectionFalg
:
376 if CurrentSection
!= DT
.MODEL_META_DATA_DEFINE
or \
377 (LastSectionFalg
and CurrentSection
== DT
.MODEL_META_DATA_DEFINE
):
378 DefineSectionParsedFlag
= self
._CallSectionParsers
(CurrentSection
,
379 DefineSectionParsedFlag
, SectionLines
,
380 InfSectionCommonDefObj
, LineNo
)
382 CurrentSection
= SectionType
384 # Clear section lines
388 if HeaderStarLineNo
== -1:
389 Logger
.Error("InfParser",
391 ST
.ERR_NO_SOURCE_HEADER
,
393 if BinaryHeaderStarLineNo
> -1 and HeaderStarLineNo
> -1 and HeaderStarLineNo
> BinaryHeaderStarLineNo
:
394 Logger
.Error("InfParser",
396 ST
.ERR_BINARY_HEADER_ORDER
,
399 # EDKII INF should not have EDKI style comment
401 if EdkCommentStartPos
!= -1:
402 Logger
.Error("InfParser",
404 ST
.ERR_INF_PARSER_EDKI_COMMENT_IN_EDKII
,
406 Line
=EdkCommentStartPos
+ 1,
407 ExtraData
=OrigLines
[EdkCommentStartPos
])
410 # extract [Event] [Hob] [BootMode] sections
412 self
._ExtractEventHobBootMod
(FileLinesList
)
414 ## _CheckSectionHeaders
417 def _CheckSectionHeaders(self
, Line
, LineNo
):
418 if len(self
.SectionHeaderContent
) == 0:
419 Logger
.Error("InfParser",
421 ST
.ERR_INF_PARSER_DEFINE_SECTION_HEADER_INVALID
,
423 Line
=LineNo
, ExtraData
=Line
)
425 for SectionItem
in self
.SectionHeaderContent
:
428 # Not cover Depex/UserExtension section header
431 if SectionItem
[0].strip().upper() == DT
.TAB_INF_FIXED_PCD
.upper() or \
432 SectionItem
[0].strip().upper() == DT
.TAB_INF_PATCH_PCD
.upper() or \
433 SectionItem
[0].strip().upper() == DT
.TAB_INF_PCD_EX
.upper() or \
434 SectionItem
[0].strip().upper() == DT
.TAB_INF_PCD
.upper() or \
435 SectionItem
[0].strip().upper() == DT
.TAB_INF_FEATURE_PCD
.upper():
436 ArchList
= GetSplitValueList(SectionItem
[1].strip(), ' ')
438 ArchList
= [SectionItem
[1].strip()]
440 for Arch
in ArchList
:
441 if (not IsValidArch(Arch
)) and \
442 (SectionItem
[0].strip().upper() != DT
.TAB_DEPEX
.upper()) and \
443 (SectionItem
[0].strip().upper() != DT
.TAB_USER_EXTENSIONS
.upper()) and \
444 (SectionItem
[0].strip().upper() != DT
.TAB_COMMON_DEFINES
.upper()):
445 Logger
.Error("InfParser",
447 ST
.ERR_INF_PARSER_DEFINE_FROMAT_INVALID
%(SectionItem
[1]),
449 Line
=LineNo
, ExtraData
=Line
)
451 # Check if the ModuleType is valid
453 ChkModSectionList
= ['LIBRARYCLASSES']
454 if (self
.SectionHeaderContent
[0][0].upper() in ChkModSectionList
):
455 if SectionItem
[2].strip().upper():
456 MoudleTypeList
= GetSplitValueList(
457 SectionItem
[2].strip().upper())
458 if (not IsValidInfMoudleTypeList(MoudleTypeList
)):
459 Logger
.Error("InfParser",
461 ST
.ERR_INF_PARSER_DEFINE_FROMAT_INVALID
%(SectionItem
[2]),
462 File
=self
.FullPath
, Line
=LineNo
,
465 ## _CallSectionParsers
468 def _CallSectionParsers(self
, CurrentSection
, DefineSectionParsedFlag
,
469 SectionLines
, InfSectionCommonDefObj
, LineNo
):
470 if CurrentSection
== DT
.MODEL_META_DATA_DEFINE
:
471 if not DefineSectionParsedFlag
:
472 self
.InfDefineParser(SectionLines
,
475 InfSectionCommonDefObj
)
476 DefineSectionParsedFlag
= True
478 Logger
.Error("Parser",
480 ST
.ERR_INF_PARSER_MULTI_DEFINE_SECTION
,
482 RaiseError
= Logger
.IS_RAISE_ERROR
)
484 elif CurrentSection
== DT
.MODEL_META_DATA_BUILD_OPTION
:
485 self
.InfBuildOptionParser(SectionLines
,
486 self
.InfBuildOptionSection
,
489 elif CurrentSection
== DT
.MODEL_EFI_LIBRARY_CLASS
:
490 self
.InfLibraryParser(SectionLines
,
491 self
.InfLibraryClassSection
,
494 elif CurrentSection
== DT
.MODEL_META_DATA_PACKAGE
:
495 self
.InfPackageParser(SectionLines
,
496 self
.InfPackageSection
,
499 # [Pcd] Sections, put it together
501 elif CurrentSection
== DT
.MODEL_PCD_FIXED_AT_BUILD
or \
502 CurrentSection
== DT
.MODEL_PCD_PATCHABLE_IN_MODULE
or \
503 CurrentSection
== DT
.MODEL_PCD_FEATURE_FLAG
or \
504 CurrentSection
== DT
.MODEL_PCD_DYNAMIC_EX
or \
505 CurrentSection
== DT
.MODEL_PCD_DYNAMIC
:
506 self
.InfPcdParser(SectionLines
,
510 elif CurrentSection
== DT
.MODEL_EFI_SOURCE_FILE
:
511 self
.InfSourceParser(SectionLines
,
512 self
.InfSourcesSection
,
515 elif CurrentSection
== DT
.MODEL_META_DATA_USER_EXTENSION
:
516 self
.InfUserExtensionParser(SectionLines
,
517 self
.InfUserExtensionSection
,
520 elif CurrentSection
== DT
.MODEL_EFI_PROTOCOL
:
521 self
.InfProtocolParser(SectionLines
,
522 self
.InfProtocolSection
,
525 elif CurrentSection
== DT
.MODEL_EFI_PPI
:
526 self
.InfPpiParser(SectionLines
,
530 elif CurrentSection
== DT
.MODEL_EFI_GUID
:
531 self
.InfGuidParser(SectionLines
,
535 elif CurrentSection
== DT
.MODEL_EFI_DEPEX
:
536 self
.InfDepexParser(SectionLines
,
537 self
.InfDepexSection
,
540 elif CurrentSection
== DT
.MODEL_EFI_BINARY_FILE
:
541 self
.InfBinaryParser(SectionLines
,
542 self
.InfBinariesSection
,
545 # Unknown section type found, raise error.
548 if len(self
.SectionHeaderContent
) >= 1:
549 Logger
.Error("Parser",
551 ST
.ERR_INF_PARSER_UNKNOWN_SECTION
,
552 File
=self
.FullPath
, Line
=LineNo
,
553 RaiseError
= Logger
.IS_RAISE_ERROR
)
555 Logger
.Error("Parser",
557 ST
.ERR_INF_PARSER_NO_SECTION_ERROR
,
558 File
=self
.FullPath
, Line
=LineNo
,
559 RaiseError
= Logger
.IS_RAISE_ERROR
)
561 return DefineSectionParsedFlag
563 def _ExtractEventHobBootMod(self
, FileLinesList
):
564 SpecialSectionStart
= False
565 CheckLocation
= False
566 GFindSpecialCommentRe
= \
567 re
.compile(r
"""#(?:\s*)\[(.*?)\](?:.*)""", re
.DOTALL
)
568 GFindNewSectionRe2
= \
569 re
.compile(r
"""#?(\s*)\[(.*?)\](.*)""", re
.DOTALL
)
572 for Line
in FileLinesList
:
575 MatchObject
= GFindSpecialCommentRe
.search(Line
)
577 SpecialSectionStart
= True
579 if MatchObject
.group(1).upper().startswith("EVENT"):
580 List
= self
.EventList
581 elif MatchObject
.group(1).upper().startswith("HOB"):
583 elif MatchObject
.group(1).upper().startswith("BOOTMODE"):
584 List
= self
.BootModeList
586 SpecialSectionStart
= False
587 CheckLocation
= False
588 if SpecialSectionStart
:
589 Element
.append([Line
, LineNum
])
593 # if currently in special section, try to detect end of current section
595 MatchObject
= GFindNewSectionRe2
.search(Line
)
596 if SpecialSectionStart
:
598 SpecialSectionStart
= False
599 CheckLocation
= False
602 SpecialSectionStart
= False
606 if not Line
.startswith(DT
.TAB_COMMENT_SPLIT
):
607 Logger
.Warn("Parser",
608 ST
.WARN_SPECIAL_SECTION_LOCATION_WRONG
,
609 File
=self
.FullPath
, Line
=LineNum
)
610 SpecialSectionStart
= False
611 CheckLocation
= False
614 Element
.append([Line
, LineNum
])
618 CheckLocation
= False
620 Logger
.Warn("Parser",
621 ST
.WARN_SPECIAL_SECTION_LOCATION_WRONG
,
622 File
=self
.FullPath
, Line
=LineNum
)
623 CheckLocation
= False
625 if len(self
.BootModeList
) >= 1:
626 self
.InfSpecialCommentParser(self
.BootModeList
,
627 self
.InfSpecialCommentSection
,
629 DT
.TYPE_BOOTMODE_SECTION
)
631 if len(self
.EventList
) >= 1:
632 self
.InfSpecialCommentParser(self
.EventList
,
633 self
.InfSpecialCommentSection
,
635 DT
.TYPE_EVENT_SECTION
)
637 if len(self
.HobList
) >= 1:
638 self
.InfSpecialCommentParser(self
.HobList
,
639 self
.InfSpecialCommentSection
,
642 ## _ProcessLastSection
645 def _ProcessLastSection(self
, SectionLines
, Line
, LineNo
, CurrentSection
):
647 # The last line is a section header. will discard it.
649 if not (Line
.startswith(DT
.TAB_SECTION_START
) and Line
.find(DT
.TAB_SECTION_END
) > -1):
650 SectionLines
.append((Line
, LineNo
))
652 if len(self
.SectionHeaderContent
) >= 1:
653 TemSectionName
= self
.SectionHeaderContent
[0][0].upper()
654 if TemSectionName
.upper() not in gINF_SECTION_DEF
.keys():
655 Logger
.Error("InfParser",
657 ST
.ERR_INF_PARSER_UNKNOWN_SECTION
,
661 RaiseError
= Logger
.IS_RAISE_ERROR
664 CurrentSection
= gINF_SECTION_DEF
[TemSectionName
]
665 self
.LastSectionHeaderContent
= self
.SectionHeaderContent
667 return SectionLines
, CurrentSection
669 ## _ConvertSecNameToType
672 def _ConvertSecNameToType(SectionName
):
674 if SectionName
.upper() not in gINF_SECTION_DEF
.keys():
675 SectionType
= DT
.MODEL_UNKNOWN
677 SectionType
= gINF_SECTION_DEF
[SectionName
.upper()]