Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[analyzer] Add support the CC_ANALYZER_BIN env var #4057

Merged
merged 4 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,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
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
Loading