Index: tools/scan-build/CommonStuff.pm =================================================================== --- tools/scan-build/CommonStuff.pm +++ tools/scan-build/CommonStuff.pm @@ -0,0 +1,68 @@ +#!/usr/bin/env perl +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# A set of routines common to scan-build and [ccc/c++]-analyzer scripts. +# +##===----------------------------------------------------------------------===## + +package CommonStuff; +use strict; + +# Reads a section from INI (https://en.wikipedia.org/wiki/INI_file) file. +# $INIFile - path to the file to read options from. +# $SectionToRead - name of the section to read options from. +# $OptionsOut - array reference to keep output, is being filled with +# {Option =>, Value =>} elements as options are parsed. +# Preserves an order in which the options occur in config file. +sub ReadINI { + my ($INIFile, $SectionToRead, $OptionsOut) = @_; + my $CurrSection = ""; + my $ErrMsg = undef; + my %OptionNames = (); # Just to check for duplicated options in a section. + my $SectionFound = 0; + + return "$!" unless open(IN, "<", $INIFile); + + while() { + s/^\s+|\s+$//og; # remove leading and trailing whitespaces + next if (/^$/o); # skip empty lines + next if (/^[#;]/o); # skip comments + + # Parse section name. + if (/^\[([a-zA-Z0-9\-_]+)\]$/o) { + $CurrSection = $1; + $SectionFound |= $CurrSection eq $SectionToRead; + next; + } + # Parse options. + elsif (/^([a-zA-Z0-9\-_]+)\s*=\s*(.*)$/o) { + next if $CurrSection ne $SectionToRead; + if (exists $OptionNames{$1}) { + $ErrMsg = "Duplicate option '$1' in section '[$CurrSection]'."; + last; + } + $OptionNames{$1} = 1; + # Fil output array with options with nonempty values. + push @$OptionsOut, { Option => $1, Value => $2 } if $2 ne ""; + } + # Bad syntax. + else { + $ErrMsg = "Error parsing line '$_'."; + last; + } + } + + $ErrMsg = "Section '[$SectionToRead]' not found." + unless $ErrMsg || $SectionFound; + + close (IN); + return $ErrMsg; +} + +1; Index: tools/scan-build/scan-build =================================================================== --- tools/scan-build/scan-build +++ tools/scan-build/scan-build @@ -25,6 +25,9 @@ use Cwd qw/ getcwd abs_path /; use Sys::Hostname; use Hash::Util qw(lock_keys); +# Add scan-build dir to the list of places where perl looks for modules. +use lib dirname(abs_path($0)); +use CommonStuff; my $Prog = "scan-build"; my $BuildName; @@ -1439,6 +1442,118 @@ } ##----------------------------------------------------------------------------## +# Process options from config file. +##----------------------------------------------------------------------------## + +my %CfgOptToCmdArg = ( + ANALYZE_HEADERS_FLAG => "-analyze-headers", + OUTPUT_LOCATION => "-o", + KEEP_GOING_FLAG => "-k", + HTML_TITLE => "--html-title", + OUTPUT_FORMAT => undef, # Alias for -plist/-plist-html. Possible values: [plist|plist-html]. + STATUS_BUGS_FLAG => "--status-bugs", + USE_CC => "--use-cc", + USE_CPP => "--use-c++", + ANALYZER_TARGET => "--analyzer-target", + VERBOSITY_LEVEL => "-v", # Possible values: [1|2|3]. + VIEW_FLAG => "-V", + NO_FAILURE_REPORTS_FLAG => "-no-failure-reports", + STATS_FLAG => "-stats", + MAXLOOP => "-maxloop", + INTERNAL_STATS_FLAG => "-internal-stats", + USE_ANALYZER => "--use-analyzer", + KEEP_EMPTY_FLAG => "--keep-empty", + OVERRIDE_COMPILER_FLAG => "--override-compiler", + ANALYZER_CONFIG => "-analyzer-config", + ENABLE_CHECKERS => "-enable-checker", # Value: checker names separated with commas. + DISABLE_CHECKERS => "-disable-checker", # Value: checker names separated with commas. + LOAD_PLUGINS => "-load-plugin" # Value: plugin names separated with commas. +); + +# Translates options obtained from config file to scan-build command line arguments. +sub CfgOptionsToCmdArgs { + # $CfgOptions - reference to array of { Option, Value }. + # $CmdArgs - array for output. + my ($CfgOptions, $CmdArgs) = @_; + + foreach my $OptionValuePair (@$CfgOptions) { + my $Option = $$OptionValuePair{Option}; + my $Value = $$OptionValuePair{Value}; + + next if !defined $Value; + + if (!exists $CfgOptToCmdArg{$Option} ) { + print "Warning: unrecognized option in config file: '$Option'. Option ignored."; + next; + } + my $Arg = $CfgOptToCmdArg{$Option}; + + # OUTPUT_FORMAT + if ($Option eq "OUTPUT_FORMAT") { + if ($Value eq "plist") { + push @$CmdArgs, "-plist"; + } + elsif ($Value eq "plist-html") { + push @$CmdArgs, "-plist-html"; + } + else { + print "Warning: '$Option' value must be [plist|plist-html]. Option ignored.\n"; + } + } + # VERBOSITY_LEVEL + elsif ($Option eq "VERBOSITY_LEVEL") { + if ($Value !~ /\d/o || $Value < 1 || $Value > 3) { + print "Warning: '$Option' value must be [1|2|3]. Option ignored.\n"; + } + push @$CmdArgs, $Arg if ($Value > 0); + push @$CmdArgs, $Arg if ($Value > 1); + push @$CmdArgs, $Arg if ($Value > 2); + } + # ENABLE_CHECKERS, DISABLE_CHECKERS, LOAD_PLUGINS + elsif ($Option eq "ENABLE_CHECKERS" || + $Option eq "DISABLE_CHECKERS" || + $Option eq "LOAD_PLUGINS") { + foreach (split /\s*,\s*/o, $Value) { + push @$CmdArgs, $Arg; + push @$CmdArgs, $_; + } + } + # Flags: {flag_name}_FLAG + elsif ($Option =~ /_FLAG$/o) { + if ($Value eq '1') { + push @$CmdArgs, $Arg; + } + elsif ($Value ne '0') { + print "Warning: '$Option' value must be [0|1]. Option ignored.\n"; + } + } + # The rest options. + else { + push @$CmdArgs, $Arg; + push @$CmdArgs, $Value; + } + } +} + +# Config file from scan-build dir. +my $PathToCfg = dirname(abs_path($0))."/scan-build.cfg"; +# Array of { Option, Value }. +my @OptionsFromCfg; +# Options from config file translated to scan-build command line arguments. +my @ArgsFromCfg; + +my $ErrorMsg = CommonStuff::ReadINI($PathToCfg, "scan-build", \@OptionsFromCfg); +if (defined $ErrorMsg) { + print "Warning: error reading $PathToCfg: $ErrorMsg\n"; +} +else { + CfgOptionsToCmdArgs(\@OptionsFromCfg, \@ArgsFromCfg); + # Add arguments from config file to the front of @ARGV. + unshift @ARGV, @ArgsFromCfg; +} + + +##----------------------------------------------------------------------------## # Process command-line arguments. ##----------------------------------------------------------------------------## Index: tools/scan-build/scan-build.cfg =================================================================== --- tools/scan-build/scan-build.cfg +++ tools/scan-build/scan-build.cfg @@ -0,0 +1,85 @@ +# A simple INI (https://en.wikipedia.org/wiki/INI_file) file. + +[scan-build] +# This section contains scan-build options which are aliases for scan-build +# command-line arguments. This options are processed before any command line +# arguments so equivalent command line arguments will overwrite values obtained +# from this section. +# +# The order in which the options are passed to scan-build is the same in which +# they occur in this section. You can freely change the options order or delete +# options you don't like to see here. +# +# Options with no values are skipped. +# {flag_name}_FLAG options can only take values 1 and 0. + + # Alias for -analyze-headers. + ANALYZE_HEADERS_FLAG = + + # Alias for -o. + OUTPUT_LOCATION = + + # Alias for -k (--keep-going). + KEEP_GOING_FLAG = + + # Alias for --html-title. + HTML_TITLE = + + # Alias for -plist/-plist-html. + # Possible values: [plist|plist-html]. + OUTPUT_FORMAT = + + # Alias for --status-bugs. + STATUS_BUGS_FLAG = + + # Alias for --use-cc. + USE_CC = + + # Alias for --use-c++. + USE_CPP = + + # Alias for --analyzer-target. + ANALYZER_TARGET = + + # Alias for -v. + #Possible values: [1|2|3]. + VERBOSITY_LEVEL = + + # Alias for -V (--view). + VIEW_FLAG = + + # Alias for -no-failure-reports. + NO_FAILURE_REPORTS_FLAG = + + # Alias for -stats. + STATS_FLAG = + + # Alias for -maxloop. + MAXLOOP = + + # Alias for -internal-stats. + INTERNAL_STATS_FLAG = + + # Alias for --use-analyzer. + USE_ANALYZER = + + # Alias for --keep-empty. + KEEP_EMPTY_FLAG = + + # Alias for --override-compiler. + OVERRIDE_COMPILER_FLAG = + + # Alias for -analyzer-config. + ANALYZER_CONFIG = + + # Alias for -enable-checker. + # Value: checker names separated by commas. + ENABLE_CHECKERS = + + # Alias for -disable-checker. + # Value: checker names separated by commas. + DISABLE_CHECKERS = + + # Alias for -load-plugin. + # Value: plugin names separated by commas. + LOAD_PLUGINS =