Skip to content

Commit

Permalink
Merge pull request #4057 from Szelethus/env_var_executable
Browse files Browse the repository at this point in the history
[analyzer] Add support the CC_ANALYZER_BIN env var
  • Loading branch information
vodorok authored Oct 26, 2023
2 parents c054acf + 1ef096c commit afbb40b
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 1 deletion.
39 changes: 39 additions & 0 deletions analyzer/codechecker_analyzer/analyzer_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

# pylint: disable=no-name-in-module
from distutils.spawn import find_executable
from argparse import ArgumentTypeError

import os
import platform
Expand All @@ -20,6 +21,7 @@
from pathlib import Path

from codechecker_common import logger
from codechecker_analyzer.arg import analyzer_binary
from codechecker_common.checker_labels import CheckerLabels
from codechecker_common.singleton import Singleton
from codechecker_common.util import load_json
Expand Down Expand Up @@ -90,6 +92,37 @@ def __init__(self):
self.__populate_analyzers()
self.__populate_replacer()

def __parse_CC_ANALYZER_BIN(self):
env_var_bins = {}
if 'CC_ANALYZER_BIN' in self.__analyzer_env:
had_error = False
for value in self.__analyzer_env['CC_ANALYZER_BIN'].split(';'):
try:
analyzer_name, path = analyzer_binary(value)
except ArgumentTypeError as e:
LOG.error(e)
had_error = True
continue

if not os.path.isfile(path):
LOG.error(f"'{path}' is not a path to an analyzer binary "
"given to CC_ANALYZER_BIN!")
had_error = True

if had_error:
continue

LOG.info(f"Using '{path}' for analyzer '{analyzer_name}'")
env_var_bins[analyzer_name] = path

if had_error:
LOG.info("The value of CC_ANALYZER_BIN should be in the"
"format of "
"CC_ANALYZER_BIN='<analyzer1>:/path/to/bin1;"
"<analyzer2>:/path/to/bin2'")
sys.exit(1)
return env_var_bins

def __get_package_config(self):
""" Get package configuration. """
pckg_config_file = os.path.join(
Expand Down Expand Up @@ -166,8 +199,13 @@ def __populate_analyzers(self):
if not analyzer_from_path:
analyzer_env = self.analyzer_env

env_var_bin = self.__parse_CC_ANALYZER_BIN()

compiler_binaries = self.pckg_layout.get('analyzers')
for name, value in compiler_binaries.items():
if name in env_var_bin:
self.__analyzers[name] = env_var_bin[name]
continue

if analyzer_from_path:
value = os.path.basename(value)
Expand All @@ -182,6 +220,7 @@ def __populate_analyzers(self):
if not compiler_binary:
LOG.debug("'%s' binary can not be found in your PATH!",
value)
self.__analyzers[name] = None
continue

self.__analyzers[name] = os.path.realpath(compiler_binary)
Expand Down
5 changes: 4 additions & 1 deletion analyzer/codechecker_analyzer/analyzers/analyzer_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,10 @@ def check_supported_analyzers(analyzers):
error = analyzer.is_binary_version_incompatible(check_env)
if error:
failed_analyzers.add((analyzer_name,
f"Incompatible version: {error}"))
f"Incompatible version: {error} "
"Maybe try setting an absolute path to "
"a different analyzer binary via the "
"env variable CC_ANALYZER_BIN?"))
available_analyzer = False

if not analyzer_bin or \
Expand Down
4 changes: 4 additions & 0 deletions analyzer/codechecker_analyzer/analyzers/clangsa/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ def __add_plugin_load_flags(cls, analyzer_cmd: List[str]):

@classmethod
def get_binary_version(self, environ, details=False) -> str:
# No need to LOG here, we will emit a warning later anyway.
if not self.analyzer_binary():
return None

if details:
version = [self.analyzer_binary(), '--version']
else:
Expand Down
4 changes: 4 additions & 0 deletions analyzer/codechecker_analyzer/analyzers/clangtidy/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,10 @@ def analyzer_binary(cls):

@classmethod
def get_binary_version(self, environ, details=False) -> str:
# No need to LOG here, we will emit a warning later anyway.
if not self.analyzer_binary():
return None

version = [self.analyzer_binary(), '--version']
try:
output = subprocess.check_output(version,
Expand Down
3 changes: 3 additions & 0 deletions analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ def analyzer_binary(cls):
@classmethod
def get_binary_version(self, environ, details=False) -> str:
""" Get analyzer version information. """
# No need to LOG here, we will emit a warning later anyway.
if not self.analyzer_binary():
return None
version = [self.analyzer_binary(), '--version']
try:
output = subprocess.check_output(version,
Expand Down
3 changes: 3 additions & 0 deletions analyzer/codechecker_analyzer/analyzers/gcc/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ def get_binary_version(self, environ, details=False) -> str:
"""
Return the analyzer version.
"""
# No need to LOG here, we will emit a warning later anyway.
if not self.analyzer_binary():
return None
if details:
version = [self.analyzer_binary(), '--version']
else:
Expand Down
17 changes: 17 additions & 0 deletions analyzer/codechecker_analyzer/arg.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
'AnalyzerConfig', ["analyzer", "option", "value"])
CheckerConfig = collections.namedtuple(
"CheckerConfig", ["analyzer", "checker", "option", "value"])
AnalyzerBinary = collections.namedtuple(
"AnalyzerBinary", ["analyzer", "path"])


class OrderedCheckersAction(argparse.Action):
Expand Down Expand Up @@ -133,3 +135,18 @@ def checker_config(arg: str) -> CheckerConfig:
return CheckerConfig(
m.group("analyzer"), m.group("checker"),
m.group("option"), m.group("value"))


def analyzer_binary(arg: str) -> AnalyzerBinary:
"""
This function can be used at "type" argument of argparse.add_argument().
It checks the format of --analyzer_binary flag: <analyzer>:<path>
"""
m = re.match(r"(?P<analyzer>.+):(?P<path>.+)", arg)

if not m:
raise argparse.ArgumentTypeError(
f"Analyzer binary in wrong format: {arg}, should be "
"<analyzer>:</path/to/bin/>")

return AnalyzerBinary(m.group("analyzer"), m.group("path"))
5 changes: 5 additions & 0 deletions analyzer/codechecker_analyzer/cmd/analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
epilog_env_var = f"""
CC_ANALYZERS_FROM_PATH Set to `yes` or `1` to enforce taking the analyzers
from the `PATH` instead of the given binaries.
CC_ANALYZER_BIN Set the absolute paths of an analyzer binaries.
Overrides other means of CodeChecker getting hold of
binary.
Format: CC_ANALYZER_BIN='<analyzer1>:/path/to/bin1;
<analyzer2>:/path/to/bin2'
CC_CLANGSA_PLUGIN_DIR If the CC_ANALYZERS_FROM_PATH environment variable
is set you can configure the plugin directory of the
Clang Static Analyzer by using this environment
Expand Down
10 changes: 10 additions & 0 deletions docs/analyzer/user_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,11 @@ Environment variables for 'CodeChecker analyze' command:
CC_ANALYZERS_FROM_PATH Set to `yes` or `1` to enforce taking the analyzers
from the `PATH` instead of the given binaries.
CC_ANALYZER_BIN Set the absolute paths of an analyzer binaries.
Overrides other means of CodeChecker getting hold of
binary.
Format: CC_ANALYZER_BIN='<analyzer1>:/path/to/bin1;
<analyzer2>:/path/to/bin2'
CC_CLANGSA_PLUGIN_DIR If the CC_ANALYZERS_FROM_PATH environment variable
is set you can configure the plugin directory of the
Clang Static Analyzer by using this environment
Expand Down Expand Up @@ -1031,6 +1036,11 @@ Environment variables
CC_ANALYZERS_FROM_PATH Set to `yes` or `1` to enforce taking the analyzers
from the `PATH` instead of the given binaries.
CC_ANALYZER_BIN Set the absolute paths of an analyzer binaries.
Overrides other means of CodeChecker getting hold of
binary.
Format: CC_ANALYZER_BIN='<analyzer1>:/path/to/bin1;
<analyzer2>:/path/to/bin2'
CC_CLANGSA_PLUGIN_DIR If the CC_ANALYZERS_FROM_PATH environment variable
is set you can configure the plugin directory of the
Clang Static Analyzer by using this environment
Expand Down

0 comments on commit afbb40b

Please sign in to comment.