summaryrefslogtreecommitdiffstats
path: root/clang/utils/analyzer/SATestBuild.py
diff options
context:
space:
mode:
Diffstat (limited to 'clang/utils/analyzer/SATestBuild.py')
-rwxr-xr-xclang/utils/analyzer/SATestBuild.py226
1 files changed, 113 insertions, 113 deletions
diff --git a/clang/utils/analyzer/SATestBuild.py b/clang/utils/analyzer/SATestBuild.py
index 5e56afca668..e541c72c6ac 100755
--- a/clang/utils/analyzer/SATestBuild.py
+++ b/clang/utils/analyzer/SATestBuild.py
@@ -6,8 +6,8 @@ Static Analyzer qualification infrastructure.
The goal is to test the analyzer against different projects, check for failures,
compare results, and measure performance.
-Repository Directory will contain sources of the projects as well as the
-information on how to build them and the expected output.
+Repository Directory will contain sources of the projects as well as the
+information on how to build them and the expected output.
Repository Directory structure:
- ProjectMap file
- Historical Performance Data
@@ -19,16 +19,16 @@ Repository Directory structure:
Note that the build tree must be inside the project dir.
To test the build of the analyzer one would:
- - Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that
+ - Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that
the build directory does not pollute the repository to min network traffic).
- Build all projects, until error. Produce logs to report errors.
- - Compare results.
+ - Compare results.
-The files which should be kept around for failure investigations:
+The files which should be kept around for failure investigations:
RepositoryCopy/Project DirI/ScanBuildResults
- RepositoryCopy/Project DirI/run_static_analyzer.log
-
-Assumptions (TODO: shouldn't need to assume these.):
+ RepositoryCopy/Project DirI/run_static_analyzer.log
+
+Assumptions (TODO: shouldn't need to assume these.):
The script is being run from the Repository Directory.
The compiler for scan-build and scan-build are in the PATH.
export PATH=/Users/zaks/workspace/c2llvm/build/Release+Asserts/bin:$PATH
@@ -36,7 +36,7 @@ Assumptions (TODO: shouldn't need to assume these.):
For more logging, set the env variables:
zaks:TI zaks$ export CCC_ANALYZER_LOG=1
zaks:TI zaks$ export CCC_ANALYZER_VERBOSE=1
-
+
The list of checkers tested are hardcoded in the Checkers variable.
For testing additional checkers, use the SA_ADDITIONAL_CHECKERS environment
variable. It should contain a comma separated list.
@@ -120,16 +120,16 @@ class flushfile(object):
sys.stdout = flushfile(sys.stdout)
def getProjectMapPath():
- ProjectMapPath = os.path.join(os.path.abspath(os.curdir),
+ ProjectMapPath = os.path.join(os.path.abspath(os.curdir),
ProjectMapFile)
if not os.path.exists(ProjectMapPath):
print "Error: Cannot find the Project Map file " + ProjectMapPath +\
"\nRunning script for the wrong directory?"
- sys.exit(-1)
- return ProjectMapPath
+ sys.exit(-1)
+ return ProjectMapPath
def getProjectDir(ID):
- return os.path.join(os.path.abspath(os.curdir), ID)
+ return os.path.join(os.path.abspath(os.curdir), ID)
def getSBOutputDirName(IsReferenceBuild) :
if IsReferenceBuild == True :
@@ -156,13 +156,13 @@ ProjectMapFile = "projectMap.csv"
# Names of the project specific scripts.
# The script that needs to be executed before the build can start.
CleanupScript = "cleanup_run_static_analyzer.sh"
-# This is a file containing commands for scan-build.
+# This is a file containing commands for scan-build.
BuildScript = "run_static_analyzer.cmd"
# The log file name.
LogFolderName = "Logs"
BuildLogName = "run_static_analyzer.log"
-# Summary file - contains the summary of the failures. Ex: This info can be be
+# Summary file - contains the summary of the failures. Ex: This info can be be
# displayed when buildbot detects a build failure.
NumOfFailuresInSummary = 10
FailuresSummaryFileName = "failures.txt"
@@ -189,21 +189,21 @@ def runCleanupScript(Dir, PBuildLogFile):
ScriptPath = os.path.join(Dir, CleanupScript)
if os.path.exists(ScriptPath):
try:
- if Verbose == 1:
+ if Verbose == 1:
print " Executing: %s" % (ScriptPath,)
- check_call("chmod +x %s" % ScriptPath, cwd = Dir,
+ check_call("chmod +x %s" % ScriptPath, cwd = Dir,
stderr=PBuildLogFile,
- stdout=PBuildLogFile,
- shell=True)
+ stdout=PBuildLogFile,
+ shell=True)
check_call(ScriptPath, cwd = Dir, stderr=PBuildLogFile,
- stdout=PBuildLogFile,
+ stdout=PBuildLogFile,
shell=True)
except:
print "Error: The pre-processing step failed. See ", \
PBuildLogFile.name, " for details."
sys.exit(-1)
-# Build the project with scan-build by reading in the commands and
+# Build the project with scan-build by reading in the commands and
# prefixing them with the scan-build options.
def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
BuildScriptPath = os.path.join(Dir, BuildScript)
@@ -212,9 +212,9 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
sys.exit(-1)
SBOptions = "--use-analyzer " + Clang + " "
SBOptions += "-plist-html -o " + SBOutputDir + " "
- SBOptions += "-enable-checker " + Checkers + " "
+ SBOptions += "-enable-checker " + Checkers + " "
SBOptions += "--keep-empty "
- # Always use ccc-analyze to ensure that we can locate the failures
+ # Always use ccc-analyze to ensure that we can locate the failures
# directory.
SBOptions += "--override-compiler "
try:
@@ -231,10 +231,10 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
"-j" not in Command:
Command += " -j%d" % Jobs
SBCommand = SBPrefix + Command
- if Verbose == 1:
+ if Verbose == 1:
print " Executing: %s" % (SBCommand,)
check_call(SBCommand, cwd = Dir, stderr=PBuildLogFile,
- stdout=PBuildLogFile,
+ stdout=PBuildLogFile,
shell=True)
except:
print "Error: scan-build failed. See ",PBuildLogFile.name,\
@@ -249,97 +249,97 @@ def hasNoExtension(FileName):
def isValidSingleInputFile(FileName):
(Root, Ext) = os.path.splitext(FileName)
- if ((Ext == ".i") | (Ext == ".ii") |
- (Ext == ".c") | (Ext == ".cpp") |
+ if ((Ext == ".i") | (Ext == ".ii") |
+ (Ext == ".c") | (Ext == ".cpp") |
(Ext == ".m") | (Ext == "")) :
return True
return False
-
+
# Run analysis on a set of preprocessed files.
def runAnalyzePreprocessed(Dir, SBOutputDir, Mode):
if os.path.exists(os.path.join(Dir, BuildScript)):
print "Error: The preprocessed files project should not contain %s" % \
BuildScript
- raise Exception()
+ raise Exception()
CmdPrefix = Clang + " -cc1 -analyze -analyzer-output=plist -w "
- CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks "
-
+ CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks "
+
if (Mode == 2) :
- CmdPrefix += "-std=c++11 "
-
+ CmdPrefix += "-std=c++11 "
+
PlistPath = os.path.join(Dir, SBOutputDir, "date")
FailPath = os.path.join(PlistPath, "failures");
os.makedirs(FailPath);
-
+
for FullFileName in glob.glob(Dir + "/*"):
FileName = os.path.basename(FullFileName)
Failed = False
-
+
# Only run the analyzes on supported files.
if (hasNoExtension(FileName)):
continue
if (isValidSingleInputFile(FileName) == False):
print "Error: Invalid single input file %s." % (FullFileName,)
raise Exception()
-
+
# Build and call the analyzer command.
OutputOption = "-o " + os.path.join(PlistPath, FileName) + ".plist "
Command = CmdPrefix + OutputOption + FileName
LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b")
try:
- if Verbose == 1:
+ if Verbose == 1:
print " Executing: %s" % (Command,)
check_call(Command, cwd = Dir, stderr=LogFile,
- stdout=LogFile,
+ stdout=LogFile,
shell=True)
except CalledProcessError, e:
print "Error: Analyzes of %s failed. See %s for details." \
"Error code %d." % \
(FullFileName, LogFile.name, e.returncode)
- Failed = True
+ Failed = True
finally:
- LogFile.close()
-
+ LogFile.close()
+
# If command did not fail, erase the log file.
if Failed == False:
os.remove(LogFile.name);
def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
- TBegin = time.time()
+ TBegin = time.time()
BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName)
- print "Log file: %s" % (BuildLogPath,)
+ print "Log file: %s" % (BuildLogPath,)
print "Output directory: %s" %(SBOutputDir, )
-
+
# Clean up the log file.
if (os.path.exists(BuildLogPath)) :
RmCommand = "rm " + BuildLogPath
if Verbose == 1:
print " Executing: %s" % (RmCommand,)
check_call(RmCommand, shell=True)
-
+
# Clean up scan build results.
if (os.path.exists(SBOutputDir)) :
RmCommand = "rm -r " + SBOutputDir
- if Verbose == 1:
+ if Verbose == 1:
print " Executing: %s" % (RmCommand,)
check_call(RmCommand, shell=True)
assert(not os.path.exists(SBOutputDir))
os.makedirs(os.path.join(SBOutputDir, LogFolderName))
-
+
# Open the log file.
PBuildLogFile = open(BuildLogPath, "wb+")
-
+
# Build and analyze the project.
try:
runCleanupScript(Dir, PBuildLogFile)
-
+
if (ProjectBuildMode == 1):
runScanBuild(Dir, SBOutputDir, PBuildLogFile)
else:
runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode)
-
+
if IsReferenceBuild :
runCleanupScript(Dir, PBuildLogFile)
@@ -354,28 +354,28 @@ def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
else SourceFile for SourceFile in Data['files']]
Data['files'] = Paths
plistlib.writePlist(Data, Plist)
-
+
finally:
PBuildLogFile.close()
-
+
print "Build complete (time: %.2f). See the log for more details: %s" % \
- ((time.time()-TBegin), BuildLogPath)
-
+ ((time.time()-TBegin), BuildLogPath)
+
# A plist file is created for each call to the analyzer(each source file).
-# We are only interested on the once that have bug reports, so delete the rest.
+# We are only interested on the once that have bug reports, so delete the rest.
def CleanUpEmptyPlists(SBOutputDir):
for F in glob.glob(SBOutputDir + "/*/*.plist"):
P = os.path.join(SBOutputDir, F)
-
+
Data = plistlib.readPlist(P)
# Delete empty reports.
if not Data['files']:
os.remove(P)
continue
-# Given the scan-build output directory, checks if the build failed
-# (by searching for the failures directories). If there are failures, it
-# creates a summary file in the output directory.
+# Given the scan-build output directory, checks if the build failed
+# (by searching for the failures directories). If there are failures, it
+# creates a summary file in the output directory.
def checkBuild(SBOutputDir):
# Check if there are failures.
Failures = glob.glob(SBOutputDir + "/*/failures/*.stderr.txt")
@@ -386,37 +386,37 @@ def checkBuild(SBOutputDir):
print "Number of bug reports (non-empty plist files) produced: %d" %\
len(Plists)
return;
-
+
# Create summary file to display when the build fails.
SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName)
if (Verbose > 0):
print " Creating the failures summary file %s" % (SummaryPath,)
-
+
SummaryLog = open(SummaryPath, "w+")
try:
SummaryLog.write("Total of %d failures discovered.\n" % (TotalFailed,))
if TotalFailed > NumOfFailuresInSummary:
- SummaryLog.write("See the first %d below.\n"
+ SummaryLog.write("See the first %d below.\n"
% (NumOfFailuresInSummary,))
# TODO: Add a line "See the results folder for more."
-
+
FailuresCopied = NumOfFailuresInSummary
Idx = 0
for FailLogPathI in Failures:
if Idx >= NumOfFailuresInSummary:
break;
- Idx += 1
+ Idx += 1
SummaryLog.write("\n-- Error #%d -----------\n" % (Idx,));
FailLogI = open(FailLogPathI, "r");
- try:
+ try:
shutil.copyfileobj(FailLogI, SummaryLog);
finally:
FailLogI.close()
finally:
SummaryLog.close()
-
+
print "Error: analysis failed. See ", SummaryPath
- sys.exit(-1)
+ sys.exit(-1)
# Auxiliary object to discard stdout.
class Discarder(object):
@@ -428,44 +428,44 @@ class Discarder(object):
# 0 - success if there are no crashes or analyzer failure.
# 1 - success if there are no difference in the number of reported bugs.
# 2 - success if all the bug reports are identical.
-def runCmpResults(Dir, Strictness = 0):
- TBegin = time.time()
+def runCmpResults(Dir, Strictness = 0):
+ TBegin = time.time()
RefDir = os.path.join(Dir, SBOutputDirReferencePrefix + SBOutputDirName)
NewDir = os.path.join(Dir, SBOutputDirName)
-
+
# We have to go one level down the directory tree.
- RefList = glob.glob(RefDir + "/*")
+ RefList = glob.glob(RefDir + "/*")
NewList = glob.glob(NewDir + "/*")
-
+
# Log folders are also located in the results dir, so ignore them.
RefLogDir = os.path.join(RefDir, LogFolderName)
if RefLogDir in RefList:
RefList.remove(RefLogDir)
NewList.remove(os.path.join(NewDir, LogFolderName))
-
+
if len(RefList) == 0 or len(NewList) == 0:
return False
assert(len(RefList) == len(NewList))
- # There might be more then one folder underneath - one per each scan-build
+ # There might be more then one folder underneath - one per each scan-build
# command (Ex: one for configure and one for make).
if (len(RefList) > 1):
# Assume that the corresponding folders have the same names.
RefList.sort()
NewList.sort()
-
+
# Iterate and find the differences.
NumDiffs = 0
- PairList = zip(RefList, NewList)
- for P in PairList:
- RefDir = P[0]
+ PairList = zip(RefList, NewList)
+ for P in PairList:
+ RefDir = P[0]
NewDir = P[1]
-
- assert(RefDir != NewDir)
- if Verbose == 1:
+
+ assert(RefDir != NewDir)
+ if Verbose == 1:
print " Comparing Results: %s %s" % (RefDir, NewDir)
-
+
DiffsPath = os.path.join(NewDir, DiffsSummaryFileName)
Opts = CmpRuns.CmpOptions(DiffsPath, "", Dir)
# Discard everything coming out of stdout (CmpRun produces a lot of them).
@@ -480,70 +480,70 @@ def runCmpResults(Dir, Strictness = 0):
(NumDiffs, DiffsPath,)
if Strictness >= 2 and NumDiffs > 0:
print "Error: Diffs found in strict mode (2)."
- sys.exit(-1)
+ sys.exit(-1)
elif Strictness >= 1 and ReportsInRef != ReportsInNew:
print "Error: The number of results are different in strict mode (1)."
- sys.exit(-1)
-
- print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin)
+ sys.exit(-1)
+
+ print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin)
return (NumDiffs > 0)
-
+
def updateSVN(Mode, ProjectsMap):
try:
- ProjectsMap.seek(0)
+ ProjectsMap.seek(0)
for I in csv.reader(ProjectsMap):
- ProjName = I[0]
+ ProjName = I[0]
Path = os.path.join(ProjName, getSBOutputDirName(True))
-
+
if Mode == "delete":
Command = "svn delete %s" % (Path,)
else:
Command = "svn add %s" % (Path,)
- if Verbose == 1:
+ if Verbose == 1:
print " Executing: %s" % (Command,)
- check_call(Command, shell=True)
-
+ check_call(Command, shell=True)
+
if Mode == "delete":
CommitCommand = "svn commit -m \"[analyzer tests] Remove " \
- "reference results.\""
+ "reference results.\""
else:
CommitCommand = "svn commit -m \"[analyzer tests] Add new " \
"reference results.\""
- if Verbose == 1:
+ if Verbose == 1:
print " Executing: %s" % (CommitCommand,)
- check_call(CommitCommand, shell=True)
+ check_call(CommitCommand, shell=True)
except:
print "Error: SVN update failed."
sys.exit(-1)
-
+
def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None, Strictness = 0):
print " \n\n--- Building project %s" % (ID,)
- TBegin = time.time()
+ TBegin = time.time()
if Dir is None :
- Dir = getProjectDir(ID)
- if Verbose == 1:
+ Dir = getProjectDir(ID)
+ if Verbose == 1:
print " Build directory: %s." % (Dir,)
-
+
# Set the build results directory.
RelOutputDir = getSBOutputDirName(IsReferenceBuild)
SBOutputDir = os.path.join(Dir, RelOutputDir)
-
+
buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild)
checkBuild(SBOutputDir)
-
+
if IsReferenceBuild == False:
runCmpResults(Dir, Strictness)
-
+
print "Completed tests for project %s (time: %.2f)." % \
(ID, (time.time()-TBegin))
-
+
def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0):
PMapFile = open(getProjectMapPath(), "rb")
- try:
+ try:
# Validate the input.
for I in csv.reader(PMapFile):
if (len(I) != 2) :
@@ -552,16 +552,16 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0):
if (not ((I[1] == "0") | (I[1] == "1") | (I[1] == "2"))):
print "Error: Second entry in the ProjectMapFile should be 0" \
" (single file), 1 (project), or 2(single file c++11)."
- raise Exception()
+ raise Exception()
- # When we are regenerating the reference results, we might need to
+ # When we are regenerating the reference results, we might need to
# update svn. Remove reference results from SVN.
if UpdateSVN == True:
assert(IsReferenceBuild == True);
updateSVN("delete", PMapFile);
-
+
# Test the projects.
- PMapFile.seek(0)
+ PMapFile.seek(0)
for I in csv.reader(PMapFile):
testProject(I[0], int(I[1]), IsReferenceBuild, None, Strictness)
@@ -571,10 +571,10 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0):
except:
print "Error occurred. Premature termination."
- raise
+ raise
finally:
- PMapFile.close()
-
+ PMapFile.close()
+
if __name__ == '__main__':
# Parse command line arguments.
Parser = argparse.ArgumentParser(description='Test the Clang Static Analyzer.')
OpenPOWER on IntegriCloud