]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/UPT/Parser/InfParser.py
Sync BaseTool trunk (version r2423) into EDKII BaseTools. The change mainly includes:
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Parser / InfParser.py
1 ## @file
2 # This file contained the parser for INF file
3 #
4 # Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
5 #
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
10 #
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.
13 #
14
15 '''
16 InfParser
17 '''
18
19 ##
20 # Import Modules
21 #
22 import re
23 import os
24 from copy import deepcopy
25
26 from Library.String import GetSplitValueList
27 from Library.String 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
35
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
41
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
46
47 ## OpenInfFile
48 #
49 #
50 def OpenInfFile(Filename):
51 FileLinesList = []
52
53 try:
54 FInputfile = open(Filename, "rb", 0)
55 try:
56 FileLinesList = FInputfile.readlines()
57 except BaseException:
58 Logger.Error("InfParser",
59 FILE_READ_FAILURE,
60 ST.ERR_FILE_OPEN_FAILURE,
61 File=Filename)
62 finally:
63 FInputfile.close()
64 except BaseException:
65 Logger.Error("InfParser",
66 FILE_READ_FAILURE,
67 ST.ERR_FILE_OPEN_FAILURE,
68 File=Filename)
69
70 return FileLinesList
71
72 ## InfParser
73 #
74 # This class defined the structure used in InfParser object
75 #
76 # @param InfObject: Inherited from InfSectionParser class
77 # @param Filename: Input value for Filename of INF file, default is
78 # None
79 # @param WorkspaceDir: Input value for current workspace directory,
80 # default is None
81 #
82 class InfParser(InfSectionParser):
83
84 def __init__(self, Filename = None, WorkspaceDir = None):
85
86 #
87 # Call parent class construct function
88 #
89 super(InfParser, self).__init__()
90
91 self.WorkspaceDir = WorkspaceDir
92 self.SupArchList = DT.ARCH_LIST
93 self.EventList = []
94 self.HobList = []
95 self.BootModeList = []
96
97 #
98 # Load Inf file if filename is not None
99 #
100 if Filename != None:
101 self.ParseInfFile(Filename)
102
103 ## Parse INF file
104 #
105 # Parse the file if it exists
106 #
107 # @param Filename: Input value for filename of INF file
108 #
109 def ParseInfFile(self, Filename):
110
111 Filename = NormPath(Filename)
112 (Path, Name) = os.path.split(Filename)
113 self.FullPath = Filename
114 self.RelaPath = Path
115 self.FileName = Name
116 GlobalData.gINF_MODULE_DIR = Path
117 GlobalData.gINF_MODULE_NAME = self.FullPath
118 GlobalData.gIS_BINARY_INF = False
119 #
120 # Initialize common data
121 #
122 LineNo = 0
123 CurrentSection = DT.MODEL_UNKNOWN
124 SectionLines = []
125
126 #
127 # Flags
128 #
129 HeaderCommentStart = False
130 HeaderCommentEnd = False
131
132 #
133 # While Section ends. parse whole section contents.
134 #
135 NewSectionStartFlag = False
136 FirstSectionStartFlag = False
137
138 #
139 # Parse file content
140 #
141 CommentBlock = []
142
143 #
144 # Variables for Event/Hob/BootMode
145 #
146 self.EventList = []
147 self.HobList = []
148 self.BootModeList = []
149 SectionType = ''
150
151 FileLinesList = OpenInfFile (Filename)
152
153 #
154 # One INF file can only has one [Defines] section.
155 #
156 DefineSectionParsedFlag = False
157
158 #
159 # Convert special characters in lines to space character.
160 #
161 FileLinesList = ConvertSpecialChar(FileLinesList)
162
163 #
164 # Process Line Extender
165 #
166 FileLinesList = ProcessLineExtender(FileLinesList)
167
168 #
169 # Process EdkI INF style comment if found
170 #
171 OrigLines = [Line for Line in FileLinesList]
172 FileLinesList, EdkCommentStartPos = ProcessEdkComment(FileLinesList)
173
174 #
175 # Judge whether the INF file is Binary INF or not
176 #
177 if IsBinaryInf(FileLinesList):
178 GlobalData.gIS_BINARY_INF = True
179
180 InfSectionCommonDefObj = None
181
182 for Line in FileLinesList:
183 LineNo = LineNo + 1
184 Line = Line.strip()
185 if (LineNo < len(FileLinesList) - 1):
186 NextLine = FileLinesList[LineNo].strip()
187
188 #
189 # blank line
190 #
191 if (Line == '' or not Line) and LineNo == len(FileLinesList):
192 LastSectionFalg = True
193
194 #
195 # check whether file header comment section started
196 #
197 if Line.startswith(DT.TAB_SPECIAL_COMMENT) and \
198 (Line.find(DT.TAB_HEADER_COMMENT) > -1) and \
199 not HeaderCommentStart:
200 if CurrentSection != DT.MODEL_UNKNOWN:
201 Logger.Error("Parser",
202 PARSER_ERROR,
203 ST.ERR_INF_PARSER_HEADER_FILE,
204 File=Filename,
205 Line=LineNo,
206 RaiseError = Logger.IS_RAISE_ERROR)
207 else:
208 CurrentSection = DT.MODEL_META_DATA_FILE_HEADER
209 #
210 # Append the first line to section lines.
211 #
212 SectionLines.append((Line, LineNo))
213 HeaderCommentStart = True
214 continue
215
216 #
217 # Collect Header content.
218 #
219 if (Line.startswith(DT.TAB_COMMENT_SPLIT) and CurrentSection == DT.MODEL_META_DATA_FILE_HEADER) and\
220 HeaderCommentStart and not Line.startswith(DT.TAB_SPECIAL_COMMENT) and not\
221 HeaderCommentEnd and NextLine != '':
222 SectionLines.append((Line, LineNo))
223 continue
224 #
225 # Header content end
226 #
227 if (Line.startswith(DT.TAB_SPECIAL_COMMENT) or not Line.strip().startswith("#")) and HeaderCommentStart \
228 and not HeaderCommentEnd:
229 SectionLines.append((Line, LineNo))
230 HeaderCommentStart = False
231 #
232 # Call Header comment parser.
233 #
234 self.InfHeaderParser(SectionLines, self.InfHeader, self.FileName)
235 SectionLines = []
236 HeaderCommentEnd = True
237 continue
238
239 #
240 # Find a new section tab
241 # Or at the last line of INF file,
242 # need to process the last section.
243 #
244 LastSectionFalg = False
245 if LineNo == len(FileLinesList):
246 LastSectionFalg = True
247
248 if Line.startswith(DT.TAB_COMMENT_SPLIT) and not Line.startswith(DT.TAB_SPECIAL_COMMENT):
249 SectionLines.append((Line, LineNo))
250 if not LastSectionFalg:
251 continue
252
253 #
254 # Encountered a section. start with '[' and end with ']'
255 #
256 if (Line.startswith(DT.TAB_SECTION_START) and \
257 Line.find(DT.TAB_SECTION_END) > -1) or LastSectionFalg:
258 if not LastSectionFalg:
259 #
260 # check to prevent '#' inside section header
261 #
262 HeaderContent = Line[1:Line.find(DT.TAB_SECTION_END)]
263 if HeaderContent.find(DT.TAB_COMMENT_SPLIT) != -1:
264 Logger.Error("InfParser",
265 FORMAT_INVALID,
266 ST.ERR_INF_PARSER_DEFINE_SECTION_HEADER_INVALID,
267 File=self.FullPath,
268 Line=LineNo,
269 ExtraData=Line)
270
271 #
272 # Keep last time section header content for section parser
273 # usage.
274 #
275 self.LastSectionHeaderContent = deepcopy(self.SectionHeaderContent)
276
277 #
278 # TailComments in section define.
279 #
280 TailComments = ''
281 CommentIndex = Line.find(DT.TAB_COMMENT_SPLIT)
282 if CommentIndex > -1:
283 TailComments = Line[CommentIndex:]
284 Line = Line[:CommentIndex]
285
286 InfSectionCommonDefObj = InfSectionCommonDef()
287 if TailComments != '':
288 InfSectionCommonDefObj.SetTailComments(TailComments)
289 if CommentBlock != '':
290 InfSectionCommonDefObj.SetHeaderComments(CommentBlock)
291 CommentBlock = []
292 #
293 # Call section parser before section header parer to avoid encounter EDKI INF file
294 #
295 if CurrentSection == DT.MODEL_META_DATA_DEFINE:
296 DefineSectionParsedFlag = self._CallSectionParsers(CurrentSection,
297 DefineSectionParsedFlag, SectionLines,
298 InfSectionCommonDefObj, LineNo)
299 #
300 # Compare the new section name with current
301 #
302 self.SectionHeaderParser(Line, self.FileName, LineNo)
303
304 self._CheckSectionHeaders(Line, LineNo)
305
306 SectionType = _ConvertSecNameToType(self.SectionHeaderContent[0][0])
307
308 if not FirstSectionStartFlag:
309 CurrentSection = SectionType
310 FirstSectionStartFlag = True
311 else:
312 NewSectionStartFlag = True
313 else:
314 SectionLines.append((Line, LineNo))
315 continue
316
317 if LastSectionFalg:
318 SectionLines, CurrentSection = self._ProcessLastSection(SectionLines, Line, LineNo, CurrentSection)
319
320 #
321 # End of section content collect.
322 # Parser the section content collected previously.
323 #
324 if NewSectionStartFlag or LastSectionFalg:
325 if CurrentSection != DT.MODEL_META_DATA_DEFINE or \
326 (LastSectionFalg and CurrentSection == DT.MODEL_META_DATA_DEFINE):
327 DefineSectionParsedFlag = self._CallSectionParsers(CurrentSection,
328 DefineSectionParsedFlag, SectionLines,
329 InfSectionCommonDefObj, LineNo)
330
331 CurrentSection = SectionType
332 #
333 # Clear section lines
334 #
335 SectionLines = []
336 #
337 # End of for
338 #
339 #
340 # Found the first section, No file header.
341 #
342 if not DefineSectionParsedFlag:
343 Logger.Error("InfParser",
344 FORMAT_INVALID,
345 ST.ERR_INF_PARSER_HEADER_MISSGING,
346 File=self.FullPath)
347
348 #
349 # EDKII INF should not have EDKI style comment
350 #
351 if EdkCommentStartPos != -1:
352 Logger.Error("InfParser",
353 FORMAT_INVALID,
354 ST.ERR_INF_PARSER_EDKI_COMMENT_IN_EDKII,
355 File=self.FullPath,
356 Line=EdkCommentStartPos + 1,
357 ExtraData=OrigLines[EdkCommentStartPos])
358
359 #
360 # extract [Event] [Hob] [BootMode] sections
361 #
362 self._ExtractEventHobBootMod(FileLinesList)
363
364 ## _CheckSectionHeaders
365 #
366 #
367 def _CheckSectionHeaders(self, Line, LineNo):
368 if len(self.SectionHeaderContent) == 0:
369 Logger.Error("InfParser",
370 FORMAT_INVALID,
371 ST.ERR_INF_PARSER_DEFINE_SECTION_HEADER_INVALID,
372 File=self.FullPath,
373 Line=LineNo, ExtraData=Line)
374 else:
375 for SectionItem in self.SectionHeaderContent:
376 ArchList = []
377 #
378 # Not cover Depex/UserExtension section header
379 # check.
380 #
381 if SectionItem[0].strip().upper() == DT.TAB_INF_FIXED_PCD.upper() or \
382 SectionItem[0].strip().upper() == DT.TAB_INF_PATCH_PCD.upper() or \
383 SectionItem[0].strip().upper() == DT.TAB_INF_PCD_EX.upper() or \
384 SectionItem[0].strip().upper() == DT.TAB_INF_PCD.upper() or \
385 SectionItem[0].strip().upper() == DT.TAB_INF_FEATURE_PCD.upper():
386 ArchList = GetSplitValueList(SectionItem[1].strip(), ' ')
387 else:
388 ArchList = [SectionItem[1].strip()]
389
390 for Arch in ArchList:
391 if (not IsValidArch(Arch)) and \
392 (SectionItem[0].strip().upper() != DT.TAB_DEPEX.upper()) and \
393 (SectionItem[0].strip().upper() != DT.TAB_USER_EXTENSIONS.upper()) and \
394 (SectionItem[0].strip().upper() != DT.TAB_COMMON_DEFINES.upper()):
395 Logger.Error("InfParser",
396 FORMAT_INVALID,
397 ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID%(SectionItem[1]),
398 File=self.FullPath,
399 Line=LineNo, ExtraData=Line)
400 #
401 # Check if the ModuleType is valid
402 #
403 ChkModSectionList = ['LIBRARYCLASSES']
404 if (self.SectionHeaderContent[0][0].upper() in ChkModSectionList):
405 if SectionItem[2].strip().upper():
406 MoudleTypeList = GetSplitValueList(
407 SectionItem[2].strip().upper())
408 if (not IsValidInfMoudleTypeList(MoudleTypeList)):
409 Logger.Error("InfParser",
410 FORMAT_INVALID,
411 ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID%(SectionItem[2]),
412 File=self.FullPath, Line=LineNo,
413 ExtraData=Line)
414
415 ## _CallSectionParsers
416 #
417 #
418 def _CallSectionParsers(self, CurrentSection, DefineSectionParsedFlag,
419 SectionLines, InfSectionCommonDefObj, LineNo):
420 if CurrentSection == DT.MODEL_META_DATA_DEFINE:
421 if not DefineSectionParsedFlag:
422 self.InfDefineParser(SectionLines,
423 self.InfDefSection,
424 self.FullPath,
425 InfSectionCommonDefObj)
426 DefineSectionParsedFlag = True
427 else:
428 Logger.Error("Parser",
429 PARSER_ERROR,
430 ST.ERR_INF_PARSER_MULTI_DEFINE_SECTION,
431 File=self.FullPath,
432 RaiseError = Logger.IS_RAISE_ERROR)
433
434 elif CurrentSection == DT.MODEL_META_DATA_BUILD_OPTION:
435 self.InfBuildOptionParser(SectionLines,
436 self.InfBuildOptionSection,
437 self.FullPath)
438
439 elif CurrentSection == DT.MODEL_EFI_LIBRARY_CLASS:
440 self.InfLibraryParser(SectionLines,
441 self.InfLibraryClassSection,
442 self.FullPath)
443
444 elif CurrentSection == DT.MODEL_META_DATA_PACKAGE:
445 self.InfPackageParser(SectionLines,
446 self.InfPackageSection,
447 self.FullPath)
448 #
449 # [Pcd] Sections, put it together
450 #
451 elif CurrentSection == DT.MODEL_PCD_FIXED_AT_BUILD or \
452 CurrentSection == DT.MODEL_PCD_PATCHABLE_IN_MODULE or \
453 CurrentSection == DT.MODEL_PCD_FEATURE_FLAG or \
454 CurrentSection == DT.MODEL_PCD_DYNAMIC_EX or \
455 CurrentSection == DT.MODEL_PCD_DYNAMIC:
456 self.InfPcdParser(SectionLines,
457 self.InfPcdSection,
458 self.FullPath)
459
460 elif CurrentSection == DT.MODEL_EFI_SOURCE_FILE:
461 self.InfSourceParser(SectionLines,
462 self.InfSourcesSection,
463 self.FullPath)
464
465 elif CurrentSection == DT.MODEL_META_DATA_USER_EXTENSION:
466 self.InfUserExtensionParser(SectionLines,
467 self.InfUserExtensionSection,
468 self.FullPath)
469
470 elif CurrentSection == DT.MODEL_EFI_PROTOCOL:
471 self.InfProtocolParser(SectionLines,
472 self.InfProtocolSection,
473 self.FullPath)
474
475 elif CurrentSection == DT.MODEL_EFI_PPI:
476 self.InfPpiParser(SectionLines,
477 self.InfPpiSection,
478 self.FullPath)
479
480 elif CurrentSection == DT.MODEL_EFI_GUID:
481 self.InfGuidParser(SectionLines,
482 self.InfGuidSection,
483 self.FullPath)
484
485 elif CurrentSection == DT.MODEL_EFI_DEPEX:
486 self.InfDepexParser(SectionLines,
487 self.InfDepexSection,
488 self.FullPath)
489
490 elif CurrentSection == DT.MODEL_EFI_BINARY_FILE:
491 self.InfBinaryParser(SectionLines,
492 self.InfBinariesSection,
493 self.FullPath)
494 #
495 # Unknown section type found, raise error.
496 #
497 else:
498 if len(self.SectionHeaderContent) >= 1:
499 Logger.Error("Parser",
500 PARSER_ERROR,
501 ST.ERR_INF_PARSER_UNKNOWN_SECTION,
502 File=self.FullPath, Line=LineNo,
503 RaiseError = Logger.IS_RAISE_ERROR)
504 else:
505 Logger.Error("Parser",
506 PARSER_ERROR,
507 ST.ERR_INF_PARSER_NO_SECTION_ERROR,
508 File=self.FullPath, Line=LineNo,
509 RaiseError = Logger.IS_RAISE_ERROR)
510
511 return DefineSectionParsedFlag
512
513 def _ExtractEventHobBootMod(self, FileLinesList):
514 SpecialSectionStart = False
515 CheckLocation = False
516 GFindSpecialCommentRe = \
517 re.compile(r"""#(?:\s*)\[(.*?)\](?:.*)""", re.DOTALL)
518 GFindNewSectionRe2 = \
519 re.compile(r"""#?(\s*)\[(.*?)\](.*)""", re.DOTALL)
520 LineNum = 0
521 Element = []
522 for Line in FileLinesList:
523 Line = Line.strip()
524 LineNum += 1
525 MatchObject = GFindSpecialCommentRe.search(Line)
526 if MatchObject:
527 SpecialSectionStart = True
528 Element = []
529 if MatchObject.group(1).upper().startswith("EVENT"):
530 List = self.EventList
531 elif MatchObject.group(1).upper().startswith("HOB"):
532 List = self.HobList
533 elif MatchObject.group(1).upper().startswith("BOOTMODE"):
534 List = self.BootModeList
535 else:
536 SpecialSectionStart = False
537 CheckLocation = False
538 if SpecialSectionStart:
539 Element.append([Line, LineNum])
540 List.append(Element)
541 else:
542 #
543 # if currently in special section, try to detect end of current section
544 #
545 MatchObject = GFindNewSectionRe2.search(Line)
546 if SpecialSectionStart:
547 if MatchObject:
548 SpecialSectionStart = False
549 CheckLocation = False
550 Element = []
551 elif not Line:
552 SpecialSectionStart = False
553 CheckLocation = True
554 Element = []
555 else:
556 if not Line.startswith(DT.TAB_COMMENT_SPLIT):
557 Logger.Warn("Parser",
558 ST.WARN_SPECIAL_SECTION_LOCATION_WRONG,
559 File=self.FullPath, Line=LineNum)
560 SpecialSectionStart = False
561 CheckLocation = False
562 Element = []
563 else:
564 Element.append([Line, LineNum])
565 else:
566 if CheckLocation:
567 if MatchObject:
568 CheckLocation = False
569 elif Line:
570 Logger.Warn("Parser",
571 ST.WARN_SPECIAL_SECTION_LOCATION_WRONG,
572 File=self.FullPath, Line=LineNum)
573 CheckLocation = False
574
575 if len(self.BootModeList) >= 1:
576 self.InfSpecialCommentParser(self.BootModeList,
577 self.InfSpecialCommentSection,
578 self.FileName,
579 DT.TYPE_BOOTMODE_SECTION)
580
581 if len(self.EventList) >= 1:
582 self.InfSpecialCommentParser(self.EventList,
583 self.InfSpecialCommentSection,
584 self.FileName,
585 DT.TYPE_EVENT_SECTION)
586
587 if len(self.HobList) >= 1:
588 self.InfSpecialCommentParser(self.HobList,
589 self.InfSpecialCommentSection,
590 self.FileName,
591 DT.TYPE_HOB_SECTION)
592 ## _ProcessLastSection
593 #
594 #
595 def _ProcessLastSection(self, SectionLines, Line, LineNo, CurrentSection):
596 #
597 # The last line is a section header. will discard it.
598 #
599 if not (Line.startswith(DT.TAB_SECTION_START) and Line.find(DT.TAB_SECTION_END) > -1):
600 SectionLines.append((Line, LineNo))
601
602 if len(self.SectionHeaderContent) >= 1:
603 TemSectionName = self.SectionHeaderContent[0][0].upper()
604 if TemSectionName.upper() not in gINF_SECTION_DEF.keys():
605 Logger.Error("InfParser",
606 FORMAT_INVALID,
607 ST.ERR_INF_PARSER_UNKNOWN_SECTION,
608 File=self.FullPath,
609 Line=LineNo,
610 ExtraData=Line,
611 RaiseError = Logger.IS_RAISE_ERROR
612 )
613 else:
614 CurrentSection = gINF_SECTION_DEF[TemSectionName]
615 self.LastSectionHeaderContent = self.SectionHeaderContent
616
617 return SectionLines, CurrentSection
618
619 ## _ConvertSecNameToType
620 #
621 #
622 def _ConvertSecNameToType(SectionName):
623 SectionType = ''
624 if SectionName.upper() not in gINF_SECTION_DEF.keys():
625 SectionType = DT.MODEL_UNKNOWN
626 else:
627 SectionType = gINF_SECTION_DEF[SectionName.upper()]
628
629 return SectionType
630