Skip to content

Commit fa85919

Browse files
committed
Analyzer binary dependent environment
If a pre-package analyzer binary (e.g. clang) is found first, the LD_LIBRARY_PATH must be extended. On the other hand, if the analyzer binary is taken from the users machine, the original environment must be used to execute the binary. This patch introduces an analyzer binary dependent environment initialization.
1 parent 7a5784f commit fa85919

File tree

12 files changed

+187
-28
lines changed

12 files changed

+187
-28
lines changed

analyzer/codechecker_analyzer/analyzer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ def perform_analysis(args, skip_handlers, rs_handler: ReviewStatusHandler,
250250

251251
# TODO: cppcheck may require a different environment than clang.
252252
version = analyzer_types.supported_analyzers[analyzer] \
253-
.get_binary_version(context.analyzer_env)
253+
.get_binary_version(context.get_analyzer_env(analyzer))
254254
metadata_info['analyzer_statistics']['version'] = version
255255

256256
metadata_tool['analyzers'][analyzer] = metadata_info

analyzer/codechecker_analyzer/analyzer_context.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def __init__(self):
4747
self._lib_dir_path = os.environ.get('CC_LIB_DIR', '')
4848
self._data_files_dir_path = os.environ.get('CC_DATA_FILES_DIR', '')
4949

50+
5051
# Use this environment variable for testing purposes only. This
5152
# variable helps to configure which labels to use in this context.
5253
labels_dir = os.path.join(self._data_files_dir_path,
@@ -65,7 +66,8 @@ def __init__(self):
6566
self.__package_build_date = None
6667
self.__package_git_hash = None
6768
self.__analyzers = {}
68-
self.__analyzer_env = None
69+
self.__analyzer_envs = {}
70+
self.__cc_env = None
6971

7072
machine = platform.uname().machine
7173

@@ -93,9 +95,9 @@ def __init__(self):
9395

9496
def __parse_cc_analyzer_bin(self):
9597
env_var_bins = {}
96-
if 'CC_ANALYZER_BIN' in self.analyzer_env:
98+
if 'CC_ANALYZER_BIN' in self.cc_env:
9799
had_error = False
98-
for value in self.__analyzer_env['CC_ANALYZER_BIN'].split(';'):
100+
for value in self.__cc_env['CC_ANALYZER_BIN'].split(';'):
99101
try:
100102
analyzer_name, path = analyzer_binary(value)
101103
except ArgumentTypeError as e:
@@ -196,17 +198,19 @@ def __set_version(self):
196198

197199
def __populate_analyzers(self):
198200
""" Set analyzer binaries for each registered analyzers. """
199-
analyzer_env = None
201+
cc_env = None
200202
analyzer_from_path = env.is_analyzer_from_path()
201203
if not analyzer_from_path:
202-
analyzer_env = self.analyzer_env
204+
cc_env = self.cc_env
203205

204206
env_var_bin = self.__parse_cc_analyzer_bin()
205207

206208
compiler_binaries = self.pckg_layout.get('analyzers')
207209
for name, value in compiler_binaries.items():
208210
if name in env_var_bin:
211+
# For non-packaged analyzers the original env is set.
209212
self.__analyzers[name] = env_var_bin[name]
213+
self.__analyzer_envs[name] = env.get_original_env()
210214
continue
211215

212216
if analyzer_from_path:
@@ -216,8 +220,12 @@ def __populate_analyzers(self):
216220
# Check if it is a package relative path.
217221
self.__analyzers[name] = os.path.join(
218222
self._data_files_dir_path, value)
223+
# For packaged analyzers the ld_library path
224+
# must be extended with the packed libs.
225+
self.__analyzer_envs[name] =\
226+
env.extend(self.path_env_extra, self.ld_lib_path_extra)
219227
else:
220-
env_path = analyzer_env['PATH'] if analyzer_env else None
228+
env_path = cc_env['PATH'] if cc_env else None
221229
compiler_binary = which(cmd=value, path=env_path)
222230
if not compiler_binary:
223231
LOG.debug("'%s' binary can not be found in your PATH!",
@@ -226,12 +234,17 @@ def __populate_analyzers(self):
226234
continue
227235

228236
self.__analyzers[name] = os.path.realpath(compiler_binary)
237+
# For non-packaged analyzers the original env is set.
238+
self.__analyzer_envs[name] = env.get_original_env()
229239

230240
# If the compiler binary is a simlink to ccache, use the
231241
# original compiler binary.
232242
if self.__analyzers[name].endswith("/ccache"):
233243
self.__analyzers[name] = compiler_binary
234244

245+
def get_analyzer_env(self, analyzer_name):
246+
return self.__analyzer_envs[analyzer_name]
247+
235248
def __populate_replacer(self):
236249
""" Set clang-apply-replacements tool. """
237250
replacer_binary = self.pckg_layout.get('clang-apply-replacements')
@@ -240,8 +253,12 @@ def __populate_replacer(self):
240253
# Check if it is a package relative path.
241254
self.__replacer = os.path.join(self._data_files_dir_path,
242255
replacer_binary)
256+
self.__analyzer_envs['clang-apply-replacements'] =\
257+
env.extend(self.path_env_extra, self.ld_lib_path_extra)
243258
else:
244259
self.__replacer = which(replacer_binary)
260+
self.__analyzer_envs['clang-apply-replacements'] =\
261+
env.get_original_env()
245262

246263
@property
247264
def version(self):
@@ -320,11 +337,10 @@ def ld_lib_path_extra(self):
320337
return ld_paths
321338

322339
@property
323-
def analyzer_env(self):
324-
if not self.__analyzer_env:
325-
self.__analyzer_env = \
326-
env.extend(self.path_env_extra, self.ld_lib_path_extra)
327-
return self.__analyzer_env
340+
def cc_env(self):
341+
if not self.__cc_env:
342+
self.__cc_env = os.environ.copy()
343+
return self.__cc_env
328344

329345
@property
330346
def analyzer_binaries(self):

analyzer/codechecker_analyzer/analyzers/analyzer_base.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ def analyze(self, analyzer_cmd, res_handler, proc_callback=None, env=None):
111111
LOG.debug_analyzer('\n%s',
112112
' '.join([shlex.quote(x) for x in analyzer_cmd]))
113113

114+
if env is None:
115+
env = analyzer_context.get_context()\
116+
.get_analyzer_env(self.ANALYZER_NAME)
117+
114118
res_handler.analyzer_cmd = analyzer_cmd
115119
try:
116120
ret_code, stdout, stderr \
@@ -158,7 +162,10 @@ def signal_handler(signum, _):
158162
signal.signal(signal.SIGINT, signal_handler)
159163

160164
if env is None:
161-
env = analyzer_context.get_context().analyzer_env
165+
env = analyzer_context.get_context().cc_env
166+
167+
LOG.debug_analyzer('\nENV:\n')
168+
LOG.debug_analyzer(env)
162169

163170
proc = subprocess.Popen(
164171
command,

analyzer/codechecker_analyzer/analyzers/analyzer_types.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ def is_ignore_conflict_supported():
104104
proc = subprocess.Popen([context.replacer_binary, '--help'],
105105
stdout=subprocess.PIPE,
106106
stderr=subprocess.PIPE,
107-
env=context.analyzer_env,
107+
env=context
108+
.get_analyzer_env("clang-apply-replacements"),
108109
encoding="utf-8", errors="ignore")
109110
out, _ = proc.communicate()
110111
return '--ignore-insert-conflict' in out
@@ -144,7 +145,7 @@ def check_supported_analyzers(analyzers):
144145
"""
145146

146147
context = analyzer_context.get_context()
147-
check_env = context.analyzer_env
148+
check_env = context.cc_env
148149

149150
analyzer_binaries = context.analyzer_binaries
150151

analyzer/codechecker_analyzer/analyzers/clangsa/analyzer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def parse_clang_help_page(
5151
help_page = subprocess.check_output(
5252
command,
5353
stderr=subprocess.STDOUT,
54-
env=analyzer_context.get_context().analyzer_env,
54+
env=analyzer_context.get_context().get_analyzer_env("clangsa"),
5555
universal_newlines=True,
5656
encoding="utf-8",
5757
errors="ignore")
@@ -207,7 +207,7 @@ def ctu_capability(cls):
207207
if not cls.__ctu_autodetection:
208208
cls.__ctu_autodetection = CTUAutodetection(
209209
cls.analyzer_binary(),
210-
analyzer_context.get_context().analyzer_env)
210+
analyzer_context.get_context().get_analyzer_env("clangsa"))
211211

212212
return cls.__ctu_autodetection
213213

@@ -606,7 +606,7 @@ def construct_result_handler(self, buildaction, report_output,
606606
def construct_config_handler(cls, args):
607607

608608
context = analyzer_context.get_context()
609-
environ = context.analyzer_env
609+
environ = context.get_analyzer_env("clangsa")
610610

611611
handler = config_handler.ClangSAConfigHandler(environ)
612612

analyzer/codechecker_analyzer/analyzers/clangsa/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def get(clang_binary):
7777
"""
7878
compiler_version = subprocess.check_output(
7979
[clang_binary, '--version'],
80-
env=analyzer_context.get_context().analyzer_env,
80+
env=analyzer_context.get_context().get_analyzer_env("clangsa"),
8181
encoding="utf-8",
8282
errors="ignore")
8383
version_parser = ClangVersionInfoParser(clang_binary)

analyzer/codechecker_analyzer/analyzers/clangtidy/analyzer.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,8 @@ def get_analyzer_checkers(cls):
270270
if cls.__analyzer_checkers:
271271
return cls.__analyzer_checkers
272272

273-
environ = analyzer_context.get_context().analyzer_env
273+
environ = analyzer_context\
274+
.get_context().get_analyzer_env("clang-tidy")
274275
result = subprocess.check_output(
275276
[cls.analyzer_binary(), "-list-checks", "-checks=*"],
276277
env=environ,
@@ -297,7 +298,8 @@ def get_checker_config(cls):
297298
try:
298299
result = subprocess.check_output(
299300
[cls.analyzer_binary(), "-dump-config", "-checks=*"],
300-
env=analyzer_context.get_context().analyzer_env,
301+
env=analyzer_context.get_context()
302+
.get_analyzer_env("clang-tidy"),
301303
universal_newlines=True,
302304
encoding="utf-8",
303305
errors="ignore")
@@ -313,7 +315,8 @@ def get_analyzer_config(cls):
313315
try:
314316
result = subprocess.check_output(
315317
[cls.analyzer_binary(), "-dump-config", "-checks=*"],
316-
env=analyzer_context.get_context().analyzer_env,
318+
env=analyzer_context.get_context()
319+
.get_analyzer_env("clang-tidy"),
317320
universal_newlines=True,
318321
encoding="utf-8",
319322
errors="ignore")

analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ def construct_config_handler(cls, args):
393393
# No cppcheck arguments file was given in the command line.
394394
LOG.debug_analyzer(aerr)
395395

396-
check_env = context.analyzer_env
396+
check_env = context.get_analyzer_env("cppcheck")
397397

398398
# Overwrite PATH to contain only the parent of the cppcheck binary.
399399
if os.path.isabs(Cppcheck.analyzer_binary()):

analyzer/codechecker_analyzer/cmd/analyzers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def uglify(text):
186186
rows = []
187187
for analyzer_name, analyzer_class in \
188188
analyzer_types.supported_analyzers.items():
189-
check_env = context.analyzer_env
189+
check_env = context.get_analyzer_env(analyzer_name)
190190
version = analyzer_class.get_binary_version(check_env)
191191
if not version:
192192
version = 'ERROR'

analyzer/codechecker_analyzer/env.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import os
1111
import re
12+
import pickle
1213

1314
from codechecker_analyzer import analyzer_context
1415
from codechecker_common.logger import get_logger
@@ -35,6 +36,24 @@ def get_log_env(logfile, original_env):
3536
return new_env
3637

3738

39+
def get_original_env():
40+
original_env = os.environ
41+
try:
42+
original_env_file = os.environ.get('CODECHECKER_ORIGINAL_BUILD_ENV')
43+
if original_env_file:
44+
LOG.debug_analyzer('Loading original build env from: %s',
45+
original_env_file)
46+
47+
with open(original_env_file, 'rb') as env_file:
48+
original_env = pickle.load(env_file, encoding='utf-8')
49+
50+
except Exception as ex:
51+
LOG.warning(str(ex))
52+
LOG.warning('Failed to get saved original_env ')
53+
original_env = None
54+
return original_env
55+
56+
3857
def extend(path_env_extra, ld_lib_path_extra):
3958
"""Extend the checker environment.
4059

analyzer/codechecker_analyzer/host_check.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def has_analyzer_config_option(clang_bin, config_option_name):
5959
cmd,
6060
stdout=subprocess.PIPE,
6161
stderr=subprocess.PIPE,
62-
env=analyzer_context.get_context().analyzer_env,
62+
env=analyzer_context.get_context().get_analyzer_env("clangsa"),
6363
encoding="utf-8", errors="ignore")
6464
out, err = proc.communicate()
6565
LOG.debug("stdout:\n%s", out)
@@ -92,7 +92,7 @@ def has_analyzer_option(clang_bin, feature):
9292
cmd,
9393
stdout=subprocess.PIPE,
9494
stderr=subprocess.PIPE,
95-
env=analyzer_context.get_context().analyzer_env,
95+
env=analyzer_context.get_context().get_analyzer_env("clangsa"),
9696
encoding="utf-8", errors="ignore")
9797
out, err = proc.communicate()
9898
LOG.debug("stdout:\n%s", out)

0 commit comments

Comments
 (0)