summaryrefslogtreecommitdiffstats
path: root/utils/analyzer/SATestBuild.py
diff options
context:
space:
mode:
Diffstat (limited to 'utils/analyzer/SATestBuild.py')
-rw-r--r--utils/analyzer/SATestBuild.py163
1 files changed, 123 insertions, 40 deletions
diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index fd4bc8a..9412358 100644
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -42,39 +42,66 @@ import os
import csv
import sys
import glob
+import math
import shutil
import time
import plistlib
from subprocess import check_call, CalledProcessError
-# Project map stores info about all the "registered" projects.
-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.
-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
-# displayed when buildbot detects a build failure.
-NumOfFailuresInSummary = 10
-FailuresSummaryFileName = "failures.txt"
-# Summary of the result diffs.
-DiffsSummaryFileName = "diffs.txt"
-
-# The scan-build result directory.
-SBOutputDirName = "ScanBuildResults"
-SBOutputDirReferencePrefix = "Ref"
-
-# The list of checkers used during analyzes.
-# Currently, consists of all the non experimental checkers.
-Checkers="experimental.security.taint,core,deadcode,security,unix,osx"
-
-Verbose = 1
+#------------------------------------------------------------------------------
+# Helper functions.
+#------------------------------------------------------------------------------
+
+def detectCPUs():
+ """
+ Detects the number of CPUs on a system. Cribbed from pp.
+ """
+ # Linux, Unix and MacOS:
+ if hasattr(os, "sysconf"):
+ if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
+ # Linux & Unix:
+ ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
+ if isinstance(ncpus, int) and ncpus > 0:
+ return ncpus
+ else: # OSX:
+ return int(capture(['sysctl', '-n', 'hw.ncpu']))
+ # Windows:
+ if os.environ.has_key("NUMBER_OF_PROCESSORS"):
+ ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
+ if ncpus > 0:
+ return ncpus
+ return 1 # Default
+
+def which(command, paths = None):
+ """which(command, [paths]) - Look up the given command in the paths string
+ (or the PATH environment variable, if unspecified)."""
+
+ if paths is None:
+ paths = os.environ.get('PATH','')
+
+ # Check for absolute match first.
+ if os.path.exists(command):
+ return command
+
+ # Would be nice if Python had a lib function for this.
+ if not paths:
+ paths = os.defpath
+
+ # Get suffixes to search.
+ # On Cygwin, 'PATHEXT' may exist but it should not be used.
+ if os.pathsep == ';':
+ pathext = os.environ.get('PATHEXT', '').split(';')
+ else:
+ pathext = ['']
+
+ # Search the paths...
+ for path in paths.split(os.pathsep):
+ for ext in pathext:
+ p = os.path.join(path, command + ext)
+ if os.path.exists(p):
+ return p
+
+ return None
# Make sure we flush the output after every print statement.
class flushfile(object):
@@ -104,6 +131,52 @@ def getSBOutputDirName(IsReferenceBuild) :
else :
return SBOutputDirName
+#------------------------------------------------------------------------------
+# Configuration setup.
+#------------------------------------------------------------------------------
+
+# Find Clang for static analysis.
+Clang = which("clang", os.environ['PATH'])
+if not Clang:
+ print "Error: cannot find 'clang' in PATH"
+ sys.exit(-1)
+
+# Number of jobs.
+Jobs = math.ceil(detectCPUs() * 0.75)
+
+# Project map stores info about all the "registered" projects.
+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.
+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
+# displayed when buildbot detects a build failure.
+NumOfFailuresInSummary = 10
+FailuresSummaryFileName = "failures.txt"
+# Summary of the result diffs.
+DiffsSummaryFileName = "diffs.txt"
+
+# The scan-build result directory.
+SBOutputDirName = "ScanBuildResults"
+SBOutputDirReferencePrefix = "Ref"
+
+# The list of checkers used during analyzes.
+# Currently, consists of all the non experimental checkers.
+Checkers="alpha.unix.SimpleStream,alpha.security.taint,core,deadcode,security,unix,osx"
+
+Verbose = 1
+
+#------------------------------------------------------------------------------
+# Test harness logic.
+#------------------------------------------------------------------------------
+
# Run pre-processing script if any.
def runCleanupScript(Dir, PBuildLogFile):
ScriptPath = os.path.join(Dir, CleanupScript)
@@ -129,13 +202,19 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
BuildScriptPath = os.path.join(Dir, BuildScript)
if not os.path.exists(BuildScriptPath):
print "Error: build script is not defined: %s" % BuildScriptPath
- sys.exit(-1)
- SBOptions = "-plist-html -o " + SBOutputDir + " "
+ sys.exit(-1)
+ SBOptions = "--use-analyzer " + Clang + " "
+ SBOptions += "-plist-html -o " + SBOutputDir + " "
SBOptions += "-enable-checker " + Checkers + " "
try:
SBCommandFile = open(BuildScriptPath, "r")
SBPrefix = "scan-build " + SBOptions + " "
for Command in SBCommandFile:
+ # If using 'make', auto imply a -jX argument
+ # to speed up analysis. xcodebuild will
+ # automatically use the maximum number of cores.
+ if Command.startswith("make "):
+ Command += "-j" + Jobs
SBCommand = SBPrefix + Command
if Verbose == 1:
print " Executing: %s" % (SBCommand,)
@@ -160,17 +239,20 @@ def isValidSingleInputFile(FileName):
(Ext == ".m") | (Ext == "")) :
return True
return False
-
+
# Run analysis on a set of preprocessed files.
-def runAnalyzePreprocessed(Dir, SBOutputDir):
+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()
- CmdPrefix = "clang -cc1 -analyze -analyzer-output=plist -w "
+ CmdPrefix = Clang + " -cc1 -analyze -analyzer-output=plist -w "
CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks "
+ if (Mode == 2) :
+ CmdPrefix += "-std=c++11 "
+
PlistPath = os.path.join(Dir, SBOutputDir, "date")
FailPath = os.path.join(PlistPath, "failures");
os.makedirs(FailPath);
@@ -208,7 +290,7 @@ def runAnalyzePreprocessed(Dir, SBOutputDir):
if Failed == False:
os.remove(LogFile.name);
-def buildProject(Dir, SBOutputDir, IsScanBuild, IsReferenceBuild):
+def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
TBegin = time.time()
BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName)
@@ -238,10 +320,10 @@ def buildProject(Dir, SBOutputDir, IsScanBuild, IsReferenceBuild):
try:
runCleanupScript(Dir, PBuildLogFile)
- if IsScanBuild:
+ if (ProjectBuildMode == 1):
runScanBuild(Dir, SBOutputDir, PBuildLogFile)
else:
- runAnalyzePreprocessed(Dir, SBOutputDir)
+ runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode)
if IsReferenceBuild :
runCleanupScript(Dir, PBuildLogFile)
@@ -395,7 +477,7 @@ def updateSVN(Mode, ProjectsMap):
print "Error: SVN update failed."
sys.exit(-1)
-def testProject(ID, IsScanBuild, IsReferenceBuild=False, Dir=None):
+def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None):
print " \n\n--- Building project %s" % (ID,)
TBegin = time.time()
@@ -409,7 +491,7 @@ def testProject(ID, IsScanBuild, IsReferenceBuild=False, Dir=None):
RelOutputDir = getSBOutputDirName(IsReferenceBuild)
SBOutputDir = os.path.join(Dir, RelOutputDir)
- buildProject(Dir, SBOutputDir, IsScanBuild, IsReferenceBuild)
+ buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild)
checkBuild(SBOutputDir)
@@ -427,8 +509,9 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False):
if (len(I) != 2) :
print "Error: Rows in the ProjectMapFile should have 3 entries."
raise Exception()
- if (not ((I[1] == "1") | (I[1] == "0"))):
- print "Error: Second entry in the ProjectMapFile should be 0 or 1."
+ 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()
# When we are regenerating the reference results, we might need to
OpenPOWER on IntegriCloud