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