]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Ecc/EccMain.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / Python / Ecc / EccMain.py
CommitLineData
30fdf114
LG
1## @file\r
2# This file is used to be the main entrance of ECC tool\r
3#\r
f7496d71 4# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
242ab73d 5# Copyright (c) Microsoft Corporation.<BR>\r
2e351cbe 6# SPDX-License-Identifier: BSD-2-Clause-Patent\r
30fdf114
LG
7#\r
8\r
9##\r
10# Import Modules\r
11#\r
b6f6b636 12from __future__ import absolute_import\r
1be2ed90 13import Common.LongFilePathOs as os, time, glob, sys\r
30fdf114 14import Common.EdkLogger as EdkLogger\r
855698fb 15from Ecc import Database\r
16from Ecc import EccGlobalData\r
17from Ecc.MetaDataParser import *\r
30fdf114 18from optparse import OptionParser\r
855698fb 19from Ecc.Configuration import Configuration\r
20from Ecc.Check import Check\r
9508d0fa 21import Common.GlobalData as GlobalData\r
d0acc87a 22\r
5a57246e 23from Common.StringUtils import NormPath\r
b36d134f 24from Common.BuildVersion import gBUILD_VERSION\r
30fdf114 25from Common import BuildToolError\r
9508d0fa 26from Common.Misc import PathClass\r
64b2609f 27from Common.Misc import DirCache\r
855698fb 28from Ecc.MetaFileWorkspace.MetaFileParser import DscParser\r
29from Ecc.MetaFileWorkspace.MetaFileParser import DecParser\r
30from Ecc.MetaFileWorkspace.MetaFileParser import InfParser\r
31from Ecc.MetaFileWorkspace.MetaFileParser import Fdf\r
32from Ecc.MetaFileWorkspace.MetaFileTable import MetaFileStorage\r
33from Ecc import c\r
fd171542 34import re, string\r
855698fb 35from Ecc.Exception import *\r
1be2ed90 36from Common.LongFilePathSupport import OpenLongFilePath as open\r
c4f52e12 37from Common.MultipleWorkspace import MultipleWorkspace as mws\r
30fdf114
LG
38\r
39## Ecc\r
40#\r
41# This class is used to define Ecc main entrance\r
42#\r
43# @param object: Inherited from object class\r
44#\r
45class Ecc(object):\r
46 def __init__(self):\r
47 # Version and Copyright\r
45258285 48 self.VersionNumber = ("1.0" + " Build " + gBUILD_VERSION)\r
30fdf114 49 self.Version = "%prog Version " + self.VersionNumber\r
f7496d71 50 self.Copyright = "Copyright (c) 2009 - 2018, Intel Corporation All rights reserved."\r
30fdf114
LG
51\r
52 self.InitDefaultConfigIni()\r
53 self.OutputFile = 'output.txt'\r
54 self.ReportFile = 'Report.csv'\r
55 self.ExceptionFile = 'exception.xml'\r
56 self.IsInit = True\r
57 self.ScanSourceCode = True\r
58 self.ScanMetaData = True\r
d0acc87a 59 self.MetaFile = ''\r
e4ac870f 60 self.OnlyScan = None\r
fd171542 61\r
30fdf114
LG
62 # Parse the options and args\r
63 self.ParseOption()\r
45258285 64 EdkLogger.info(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[00:00]" + "\n")\r
f7496d71 65\r
9508d0fa
LG
66 WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))\r
67 os.environ["WORKSPACE"] = WorkspaceDir\r
f7496d71 68\r
c4f52e12
LY
69 # set multiple workspace\r
70 PackagesPath = os.getenv("PACKAGES_PATH")\r
71 mws.setWs(WorkspaceDir, PackagesPath)\r
f7496d71 72\r
9508d0fa 73 GlobalData.gWorkspace = WorkspaceDir\r
9508d0fa
LG
74\r
75 GlobalData.gGlobalDefines["WORKSPACE"] = WorkspaceDir\r
f7496d71 76\r
45258285 77 EdkLogger.info("Loading ECC configuration ... done")\r
30fdf114
LG
78 # Generate checkpoints list\r
79 EccGlobalData.gConfig = Configuration(self.ConfigFile)\r
fd171542 80\r
30fdf114
LG
81 # Generate exception list\r
82 EccGlobalData.gException = ExceptionCheck(self.ExceptionFile)\r
fd171542 83\r
30fdf114
LG
84 # Init Ecc database\r
85 EccGlobalData.gDb = Database.Database(Database.DATABASE_PATH)\r
86 EccGlobalData.gDb.InitDatabase(self.IsInit)\r
fd171542 87\r
64b2609f
LG
88 #\r
89 # Get files real name in workspace dir\r
90 #\r
91 GlobalData.gAllFiles = DirCache(GlobalData.gWorkspace)\r
f7496d71 92\r
30fdf114 93 # Build ECC database\r
e4ac870f
LG
94# self.BuildDatabase()\r
95 self.DetectOnlyScanDirs()\r
f7496d71 96\r
30fdf114
LG
97 # Start to check\r
98 self.Check()\r
fd171542 99\r
30fdf114
LG
100 # Show report\r
101 self.GenReport()\r
fd171542 102\r
30fdf114
LG
103 # Close Database\r
104 EccGlobalData.gDb.Close()\r
105\r
106 def InitDefaultConfigIni(self):\r
107 paths = map(lambda p: os.path.join(p, 'Ecc', 'config.ini'), sys.path)\r
6ed6abd6 108 paths = (os.path.abspath('config.ini'),) + tuple(paths)\r
30fdf114
LG
109 for path in paths:\r
110 if os.path.exists(path):\r
111 self.ConfigFile = path\r
112 return\r
113 self.ConfigFile = 'config.ini'\r
114\r
e4ac870f
LG
115\r
116 ## DetectOnlyScan\r
117 #\r
118 # Detect whether only scanned folders have been enabled\r
119 #\r
120 def DetectOnlyScanDirs(self):\r
121 if self.OnlyScan == True:\r
122 OnlyScanDirs = []\r
123 # Use regex here if multiple spaces or TAB exists in ScanOnlyDirList in config.ini file\r
124 for folder in re.finditer(r'\S+', EccGlobalData.gConfig.ScanOnlyDirList):\r
125 OnlyScanDirs.append(folder.group())\r
126 if len(OnlyScanDirs) != 0:\r
127 self.BuildDatabase(OnlyScanDirs)\r
128 else:\r
129 EdkLogger.error("ECC", BuildToolError.OPTION_VALUE_INVALID, ExtraData="Use -f option need to fill specific folders in config.ini file")\r
130 else:\r
131 self.BuildDatabase()\r
f7496d71
LG
132\r
133\r
30fdf114
LG
134 ## BuildDatabase\r
135 #\r
136 # Build the database for target\r
137 #\r
e4ac870f 138 def BuildDatabase(self, SpeciDirs = None):\r
30fdf114
LG
139 # Clean report table\r
140 EccGlobalData.gDb.TblReport.Drop()\r
141 EccGlobalData.gDb.TblReport.Create()\r
fd171542 142\r
30fdf114 143 # Build database\r
f7496d71 144 if self.IsInit:\r
30fdf114 145 if self.ScanMetaData:\r
64b2609f 146 EdkLogger.quiet("Building database for Meta Data File ...")\r
e4ac870f 147 self.BuildMetaDataFileDatabase(SpeciDirs)\r
64b2609f
LG
148 if self.ScanSourceCode:\r
149 EdkLogger.quiet("Building database for Meta Data File Done!")\r
4231a819 150 if SpeciDirs is None:\r
e4ac870f
LG
151 c.CollectSourceCodeDataIntoDB(EccGlobalData.gTarget)\r
152 else:\r
153 for specificDir in SpeciDirs:\r
154 c.CollectSourceCodeDataIntoDB(os.path.join(EccGlobalData.gTarget, specificDir))\r
fd171542 155\r
30fdf114 156 EccGlobalData.gIdentifierTableList = GetTableList((MODEL_FILE_C, MODEL_FILE_H), 'Identifier', EccGlobalData.gDb)\r
e56468c0 157 EccGlobalData.gCFileList = GetFileList(MODEL_FILE_C, EccGlobalData.gDb)\r
158 EccGlobalData.gHFileList = GetFileList(MODEL_FILE_H, EccGlobalData.gDb)\r
b3d07ff8 159 EccGlobalData.gUFileList = GetFileList(MODEL_FILE_UNI, EccGlobalData.gDb)\r
fd171542 160\r
30fdf114
LG
161 ## BuildMetaDataFileDatabase\r
162 #\r
163 # Build the database for meta data files\r
164 #\r
e4ac870f
LG
165 def BuildMetaDataFileDatabase(self, SpecificDirs = None):\r
166 ScanFolders = []\r
4231a819 167 if SpecificDirs is None:\r
e4ac870f
LG
168 ScanFolders.append(EccGlobalData.gTarget)\r
169 else:\r
f7496d71 170 for specificDir in SpecificDirs:\r
e4ac870f 171 ScanFolders.append(os.path.join(EccGlobalData.gTarget, specificDir))\r
30fdf114
LG
172 EdkLogger.quiet("Building database for meta data files ...")\r
173 Op = open(EccGlobalData.gConfig.MetaDataFileCheckPathOfGenerateFileList, 'w+')\r
174 #SkipDirs = Read from config file\r
175 SkipDirs = EccGlobalData.gConfig.SkipDirList\r
c60377d7 176 SkipDirString = '|'.join(SkipDirs)\r
e4ac870f
LG
177# p = re.compile(r'.*[\\/](?:%s)[\\/]?.*' % SkipDirString)\r
178 p = re.compile(r'.*[\\/](?:%s^\S)[\\/]?.*' % SkipDirString)\r
179 for scanFolder in ScanFolders:\r
180 for Root, Dirs, Files in os.walk(scanFolder):\r
181 if p.match(Root.upper()):\r
30fdf114 182 continue\r
e4ac870f
LG
183 for Dir in Dirs:\r
184 Dirname = os.path.join(Root, Dir)\r
185 if os.path.islink(Dirname):\r
186 Dirname = os.path.realpath(Dirname)\r
187 if os.path.isdir(Dirname):\r
188 # symlinks to directories are treated as directories\r
189 Dirs.remove(Dir)\r
190 Dirs.append(Dirname)\r
f7496d71 191\r
e4ac870f
LG
192 for File in Files:\r
193 if len(File) > 4 and File[-4:].upper() == ".DEC":\r
194 Filename = os.path.normpath(os.path.join(Root, File))\r
195 EdkLogger.quiet("Parsing %s" % Filename)\r
196 Op.write("%s\r" % Filename)\r
197 #Dec(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)\r
198 self.MetaFile = DecParser(Filename, MODEL_FILE_DEC, EccGlobalData.gDb.TblDec)\r
199 self.MetaFile.Start()\r
200 continue\r
201 if len(File) > 4 and File[-4:].upper() == ".DSC":\r
202 Filename = os.path.normpath(os.path.join(Root, File))\r
203 EdkLogger.quiet("Parsing %s" % Filename)\r
204 Op.write("%s\r" % Filename)\r
205 #Dsc(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)\r
206 self.MetaFile = DscParser(PathClass(Filename, Root), MODEL_FILE_DSC, MetaFileStorage(EccGlobalData.gDb.TblDsc.Cur, Filename, MODEL_FILE_DSC, True))\r
fb0b35e0 207 # always do post-process, in case of macros change\r
e4ac870f
LG
208 self.MetaFile.DoPostProcess()\r
209 self.MetaFile.Start()\r
210 self.MetaFile._PostProcess()\r
211 continue\r
212 if len(File) > 4 and File[-4:].upper() == ".INF":\r
213 Filename = os.path.normpath(os.path.join(Root, File))\r
214 EdkLogger.quiet("Parsing %s" % Filename)\r
215 Op.write("%s\r" % Filename)\r
216 #Inf(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)\r
217 self.MetaFile = InfParser(Filename, MODEL_FILE_INF, EccGlobalData.gDb.TblInf)\r
218 self.MetaFile.Start()\r
219 continue\r
220 if len(File) > 4 and File[-4:].upper() == ".FDF":\r
221 Filename = os.path.normpath(os.path.join(Root, File))\r
222 EdkLogger.quiet("Parsing %s" % Filename)\r
223 Op.write("%s\r" % Filename)\r
224 Fdf(Filename, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)\r
225 continue\r
b3d07ff8
HC
226 if len(File) > 4 and File[-4:].upper() == ".UNI":\r
227 Filename = os.path.normpath(os.path.join(Root, File))\r
228 EdkLogger.quiet("Parsing %s" % Filename)\r
229 Op.write("%s\r" % Filename)\r
1b2467c5
HC
230 FileID = EccGlobalData.gDb.TblFile.InsertFile(Filename, MODEL_FILE_UNI)\r
231 EccGlobalData.gDb.TblReport.UpdateBelongsToItemByFile(FileID, File)\r
b3d07ff8
HC
232 continue\r
233\r
30fdf114 234 Op.close()\r
fd171542 235\r
30fdf114
LG
236 # Commit to database\r
237 EccGlobalData.gDb.Conn.commit()\r
fd171542 238\r
30fdf114 239 EdkLogger.quiet("Building database for meta data files done!")\r
fd171542 240\r
30fdf114
LG
241 ##\r
242 #\r
243 # Check each checkpoint\r
244 #\r
245 def Check(self):\r
246 EdkLogger.quiet("Checking ...")\r
247 EccCheck = Check()\r
248 EccCheck.Check()\r
249 EdkLogger.quiet("Checking done!")\r
fd171542 250\r
30fdf114
LG
251 ##\r
252 #\r
253 # Generate the scan report\r
254 #\r
255 def GenReport(self):\r
256 EdkLogger.quiet("Generating report ...")\r
257 EccGlobalData.gDb.TblReport.ToCSV(self.ReportFile)\r
258 EdkLogger.quiet("Generating report done!")\r
fd171542 259\r
30fdf114
LG
260 def GetRealPathCase(self, path):\r
261 TmpPath = path.rstrip(os.sep)\r
262 PathParts = TmpPath.split(os.sep)\r
263 if len(PathParts) == 0:\r
264 return path\r
265 if len(PathParts) == 1:\r
266 if PathParts[0].strip().endswith(':'):\r
267 return PathParts[0].upper()\r
268 # Relative dir, list . current dir\r
269 Dirs = os.listdir('.')\r
270 for Dir in Dirs:\r
271 if Dir.upper() == PathParts[0].upper():\r
272 return Dir\r
fd171542 273\r
30fdf114
LG
274 if PathParts[0].strip().endswith(':'):\r
275 PathParts[0] = PathParts[0].upper()\r
276 ParentDir = PathParts[0]\r
277 RealPath = ParentDir\r
278 if PathParts[0] == '':\r
279 RealPath = os.sep\r
280 ParentDir = os.sep\r
fd171542 281\r
30fdf114
LG
282 PathParts.remove(PathParts[0]) # need to remove the parent\r
283 for Part in PathParts:\r
284 Dirs = os.listdir(ParentDir + os.sep)\r
285 for Dir in Dirs:\r
286 if Dir.upper() == Part.upper():\r
287 RealPath += os.sep\r
288 RealPath += Dir\r
289 break\r
290 ParentDir += os.sep\r
291 ParentDir += Dir\r
fd171542 292\r
30fdf114 293 return RealPath\r
fd171542 294\r
30fdf114
LG
295 ## ParseOption\r
296 #\r
297 # Parse options\r
298 #\r
299 def ParseOption(self):\r
30fdf114 300 (Options, Target) = self.EccOptionParser()\r
fd171542 301\r
52302d4d
LG
302 if Options.Workspace:\r
303 os.environ["WORKSPACE"] = Options.Workspace\r
e56468c0 304\r
fb0b35e0 305 # Check workspace environment\r
30fdf114 306 if "WORKSPACE" not in os.environ:\r
fd171542 307 EdkLogger.error("ECC", BuildToolError.ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
30fdf114
LG
308 ExtraData="WORKSPACE")\r
309 else:\r
310 EccGlobalData.gWorkspace = os.path.normpath(os.getenv("WORKSPACE"))\r
311 if not os.path.exists(EccGlobalData.gWorkspace):\r
312 EdkLogger.error("ECC", BuildToolError.FILE_NOT_FOUND, ExtraData="WORKSPACE = %s" % EccGlobalData.gWorkspace)\r
313 os.environ["WORKSPACE"] = EccGlobalData.gWorkspace\r
314 # Set log level\r
315 self.SetLogLevel(Options)\r
fd171542 316\r
30fdf114 317 # Set other options\r
4231a819 318 if Options.ConfigFile is not None:\r
30fdf114 319 self.ConfigFile = Options.ConfigFile\r
4231a819 320 if Options.OutputFile is not None:\r
30fdf114 321 self.OutputFile = Options.OutputFile\r
4231a819 322 if Options.ReportFile is not None:\r
30fdf114 323 self.ReportFile = Options.ReportFile\r
4231a819 324 if Options.ExceptionFile is not None:\r
52302d4d 325 self.ExceptionFile = Options.ExceptionFile\r
4231a819 326 if Options.Target is not None:\r
30fdf114
LG
327 if not os.path.isdir(Options.Target):\r
328 EdkLogger.error("ECC", BuildToolError.OPTION_VALUE_INVALID, ExtraData="Target [%s] does NOT exist" % Options.Target)\r
329 else:\r
330 EccGlobalData.gTarget = self.GetRealPathCase(os.path.normpath(Options.Target))\r
331 else:\r
332 EdkLogger.warn("Ecc", EdkLogger.ECC_ERROR, "The target source tree was not specified, using current WORKSPACE instead!")\r
333 EccGlobalData.gTarget = os.path.normpath(os.getenv("WORKSPACE"))\r
4231a819 334 if Options.keepdatabase is not None:\r
30fdf114 335 self.IsInit = False\r
4231a819 336 if Options.metadata is not None and Options.sourcecode is not None:\r
30fdf114 337 EdkLogger.error("ECC", BuildToolError.OPTION_CONFLICT, ExtraData="-m and -s can't be specified at one time")\r
4231a819 338 if Options.metadata is not None:\r
30fdf114 339 self.ScanSourceCode = False\r
4231a819 340 if Options.sourcecode is not None:\r
30fdf114 341 self.ScanMetaData = False\r
4231a819 342 if Options.folders is not None:\r
e4ac870f 343 self.OnlyScan = True\r
fd171542 344\r
30fdf114
LG
345 ## SetLogLevel\r
346 #\r
347 # Set current log level of the tool based on args\r
348 #\r
fd171542 349 # @param Option: The option list including log level setting\r
30fdf114
LG
350 #\r
351 def SetLogLevel(self, Option):\r
4231a819 352 if Option.verbose is not None:\r
30fdf114 353 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
4231a819 354 elif Option.quiet is not None:\r
30fdf114 355 EdkLogger.SetLevel(EdkLogger.QUIET)\r
4231a819 356 elif Option.debug is not None:\r
30fdf114
LG
357 EdkLogger.SetLevel(Option.debug + 1)\r
358 else:\r
359 EdkLogger.SetLevel(EdkLogger.INFO)\r
360\r
361 ## Parse command line options\r
362 #\r
363 # Using standard Python module optparse to parse command line option of this tool.\r
364 #\r
365 # @retval Opt A optparse.Values object containing the parsed options\r
366 # @retval Args Target of build command\r
367 #\r
368 def EccOptionParser(self):\r
369 Parser = OptionParser(description = self.Copyright, version = self.Version, prog = "Ecc.exe", usage = "%prog [options]")\r
370 Parser.add_option("-t", "--target sourcepath", action="store", type="string", dest='Target',\r
371 help="Check all files under the target workspace.")\r
372 Parser.add_option("-c", "--config filename", action="store", type="string", dest="ConfigFile",\r
373 help="Specify a configuration file. Defaultly use config.ini under ECC tool directory.")\r
374 Parser.add_option("-o", "--outfile filename", action="store", type="string", dest="OutputFile",\r
375 help="Specify the name of an output file, if and only if one filename was specified.")\r
376 Parser.add_option("-r", "--reportfile filename", action="store", type="string", dest="ReportFile",\r
377 help="Specify the name of an report file, if and only if one filename was specified.")\r
52302d4d
LG
378 Parser.add_option("-e", "--exceptionfile filename", action="store", type="string", dest="ExceptionFile",\r
379 help="Specify the name of an exception file, if and only if one filename was specified.")\r
30fdf114
LG
380 Parser.add_option("-m", "--metadata", action="store_true", type=None, help="Only scan meta-data files information if this option is specified.")\r
381 Parser.add_option("-s", "--sourcecode", action="store_true", type=None, help="Only scan source code files information if this option is specified.")\r
382 Parser.add_option("-k", "--keepdatabase", action="store_true", type=None, help="The existing Ecc database will not be cleaned except report information if this option is specified.")\r
fd171542 383 Parser.add_option("-l", "--log filename", action="store", dest="LogFile", help="""If specified, the tool should emit the changes that\r
384 were made by the tool after printing the result message.\r
385 If filename, the emit to the file, otherwise emit to\r
386 standard output. If no modifications were made, then do not\r
30fdf114
LG
387 create a log file, or output a log message.""")\r
388 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
389 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
390 "including library instances selected, final dependency expression, "\\r
391 "and warning messages, etc.")\r
392 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
52302d4d 393 Parser.add_option("-w", "--workspace", action="store", type="string", dest='Workspace', help="Specify workspace.")\r
e4ac870f 394 Parser.add_option("-f", "--folders", action="store_true", type=None, help="Only scanning specified folders which are recorded in config.ini file.")\r
fd171542 395\r
30fdf114 396 (Opt, Args)=Parser.parse_args()\r
fd171542 397\r
30fdf114
LG
398 return (Opt, Args)\r
399\r
400##\r
401#\r
402# This acts like the main() function for the script, unless it is 'import'ed into another\r
403# script.\r
404#\r
405if __name__ == '__main__':\r
406 # Initialize log system\r
407 EdkLogger.Initialize()\r
408 EdkLogger.IsRaiseError = False\r
30fdf114 409\r
242ab73d 410 StartTime = time.perf_counter()\r
30fdf114 411 Ecc = Ecc()\r
242ab73d 412 FinishTime = time.perf_counter()\r
30fdf114
LG
413\r
414 BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime))))\r
415 EdkLogger.quiet("\n%s [%s]" % (time.strftime("%H:%M:%S, %b.%d %Y", time.localtime()), BuildDuration))\r