diff options
Diffstat (limited to 'utils/analyzer/SATestBuild.py')
| -rw-r--r-- | utils/analyzer/SATestBuild.py | 163 | 
1 files changed, 123 insertions, 40 deletions
| diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py index fd4bc8a8eeef..94123582225f 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  | 
