Skip to content

Commit b5c1dd9

Browse files
authored
Merge pull request #4475 from boegel/strict_rpath_sanity_check
disable strict RPATH sanity check by default, allow re-enabling it via `--strict-rpath-sanity-check` configuration option
2 parents 61af40b + 1b1a729 commit b5c1dd9

File tree

4 files changed

+42
-9
lines changed

4 files changed

+42
-9
lines changed

easybuild/framework/easyblock.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3200,15 +3200,21 @@ def sanity_check_rpath(self, rpath_dirs=None, check_readelf_rpath=True):
32003200

32013201
fails = []
32023202

3203-
# hard reset $LD_LIBRARY_PATH before running RPATH sanity check
3204-
orig_env = env.unset_env_vars(['LD_LIBRARY_PATH'])
3203+
if build_option('strict_rpath_sanity_check'):
3204+
self.log.info("Unsetting $LD_LIBRARY_PATH since strict RPATH sanity check is enabled...")
3205+
# hard reset $LD_LIBRARY_PATH before running RPATH sanity check
3206+
orig_env = env.unset_env_vars(['LD_LIBRARY_PATH'])
3207+
else:
3208+
self.log.info("Not unsetting $LD_LIBRARY_PATH since strict RPATH sanity check is disabled...")
3209+
orig_env = None
32053210

32063211
ld_library_path = os.getenv('LD_LIBRARY_PATH', '(empty)')
32073212
self.log.debug(f"$LD_LIBRARY_PATH during RPATH sanity check: {ld_library_path}")
32083213
modules_list = self.modules_tool.list()
32093214
self.log.debug(f"List of loaded modules: {modules_list}")
32103215

32113216
not_found_regex = re.compile(r'(\S+)\s*\=\>\s*not found')
3217+
lib_path_regex = re.compile(r'\S+\s*\=\>\s*(\S+)')
32123218
readelf_rpath_regex = re.compile('(RPATH)', re.M)
32133219

32143220
# List of libraries that should be exempt from the RPATH sanity check;
@@ -3254,6 +3260,15 @@ def sanity_check_rpath(self, rpath_dirs=None, check_readelf_rpath=True):
32543260
fail_msg = f"Library {match} not found for {path}"
32553261
self.log.warning(fail_msg)
32563262
fails.append(fail_msg)
3263+
3264+
# if any libraries were not found, log whether dependency libraries have an RPATH section
3265+
if fails:
3266+
lib_paths = re.findall(lib_path_regex, out)
3267+
for lib_path in lib_paths:
3268+
self.log.info(f"Checking whether dependency library {lib_path} has RPATH section")
3269+
res = run_shell_cmd(f"readelf -d {lib_path}", fail_on_error=False)
3270+
if res.exit_code:
3271+
self.log.info(f"No RPATH section found in {lib_path}")
32573272
else:
32583273
self.log.debug(f"Output of 'ldd {path}' checked, looks OK")
32593274

@@ -3276,7 +3291,8 @@ def sanity_check_rpath(self, rpath_dirs=None, check_readelf_rpath=True):
32763291
else:
32773292
self.log.debug(f"Not sanity checking files in non-existing directory {dirpath}")
32783293

3279-
env.restore_env_vars(orig_env)
3294+
if orig_env:
3295+
env.restore_env_vars(orig_env)
32803296

32813297
return fails
32823298

easybuild/tools/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ def mk_full_default_path(name, prefix=DEFAULT_PREFIX):
341341
'mpi_tests',
342342
'pre_create_installdir',
343343
'show_progress_bar',
344+
'strict_rpath_sanity_check',
344345
'trace',
345346
],
346347
EMPTY_LIST: [

easybuild/tools/options.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,9 @@ def override_options(self):
529529
"Git commit to use for the target software build (robot capabilities are automatically disabled)",
530530
None, 'store', None),
531531
'sticky-bit': ("Set sticky bit on newly created directories", None, 'store_true', False),
532+
'strict-rpath-sanity-check': ("Perform strict RPATH sanity check, which involces unsetting "
533+
"$LD_LIBRARY_PATH before checking whether all required libraries are found",
534+
None, 'store_true', False),
532535
'sysroot': ("Location root directory of system, prefix for standard paths like /usr/lib and /usr/include",
533536
None, 'store', None),
534537
'trace': ("Provide more information in output to stdout on progress", None, 'store_true', True, 'T'),

test/framework/toy_build.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2861,9 +2861,9 @@ def test_toy_filter_rpath_sanity_libs(self):
28612861
toy_ec = os.path.join(test_ecs, 't', 'toy-app', 'toy-app-0.0.eb')
28622862

28632863
# This should just build succesfully
2864-
args = ['--rpath']
2864+
rpath_args = ['--rpath', '--strict-rpath-sanity-check']
28652865
with self.mocked_stdout_stderr():
2866-
self._test_toy_build(ec_file=toy_ec, name='toy-app', extra_args=args, raise_error=True)
2866+
self._test_toy_build(ec_file=toy_ec, name='toy-app', extra_args=rpath_args, raise_error=True)
28672867

28682868
libtoy_libdir = os.path.join(self.test_installpath, 'software', 'libtoy', '0.0', 'lib')
28692869
toyapp_bin = os.path.join(self.test_installpath, 'software', 'toy-app', '0.0', 'bin', 'toy-app')
@@ -2884,16 +2884,16 @@ def test_toy_filter_rpath_sanity_libs(self):
28842884
# test sanity error when --rpath-filter is used to filter a required library
28852885
# In this test, libtoy.so will be linked, but not RPATH-ed due to the --rpath-filter
28862886
# Thus, the RPATH sanity check is expected to fail with libtoy.so not being found
2887+
args = rpath_args + ['--rpath-filter=.*libtoy.*']
28872888
error_pattern = r"Sanity check failed\: Library libtoy\.so not found"
28882889
with self.mocked_stdout_stderr():
28892890
self.assertErrorRegex(EasyBuildError, error_pattern, self._test_toy_build, ec_file=toy_ec,
2890-
extra_args=['--rpath', '--rpath-filter=.*libtoy.*'],
2891-
name='toy-app', raise_error=True, verbose=False)
2891+
extra_args=args, name='toy-app', raise_error=True, verbose=False)
28922892

28932893
# test use of --filter-rpath-sanity-libs option. In this test, we use --rpath-filter to make sure libtoy.so is
28942894
# not rpath-ed. Then, we use --filter-rpath-sanity-libs to make sure the RPATH sanity checks ignores
28952895
# the fact that libtoy.so is not found. Thus, this build should complete succesfully
2896-
args = ['--rpath', '--rpath-filter=.*libtoy.*', '--filter-rpath-sanity-libs=libtoy.so']
2896+
args = rpath_args + ['--rpath-filter=.*libtoy.*', '--filter-rpath-sanity-libs=libtoy.so']
28972897
with self.mocked_stdout_stderr():
28982898
self._test_toy_build(ec_file=toy_ec, name='toy-app', extra_args=args, raise_error=True)
28992899

@@ -2910,7 +2910,7 @@ def test_toy_filter_rpath_sanity_libs(self):
29102910
f"Pattern '{notfound.pattern}' should be found in: {res.output}")
29112911

29122912
# test again with list of library names passed to --filter-rpath-sanity-libs
2913-
args = ['--rpath', '--rpath-filter=.*libtoy.*', '--filter-rpath-sanity-libs=libfoo.so,libtoy.so,libbar.so']
2913+
args = rpath_args + ['--rpath-filter=.*libtoy.*', '--filter-rpath-sanity-libs=libfoo.so,libtoy.so,libbar.so']
29142914
with self.mocked_stdout_stderr():
29152915
self._test_toy_build(ec_file=toy_ec, name='toy-app', extra_args=args, raise_error=True)
29162916

@@ -2926,6 +2926,19 @@ def test_toy_filter_rpath_sanity_libs(self):
29262926
self.assertTrue(notfound.search(res.output),
29272927
f"Pattern '{notfound.pattern}' should be found in: {res.output}")
29282928

2929+
# by default, without using --strict-rpath-sanity-check, there's no failure since RPATH sanity check
2930+
# doesn't check for missing libraries with $LD_LIBRARY_PATH unset
2931+
args = ['--rpath', '--rpath-filter=.*libtoy.*']
2932+
with self.mocked_stdout_stderr():
2933+
self._test_toy_build(ec_file=toy_ec, name='toy-app', extra_args=args, raise_error=True, verbose=False)
2934+
2935+
# trouble again when $LD_LIBRARY_PATH is not used in generated module file
2936+
args = ['libtoy-0.0.eb', '--rebuild', '--rpath', '--rpath-filter=.*libtoy.*',
2937+
'--filter-env-vars=LD_LIBRARY_PATH']
2938+
with self.mocked_stdout_stderr():
2939+
self.assertErrorRegex(EasyBuildError, error_pattern, self._test_toy_build, ec_file=toy_ec,
2940+
extra_args=args, name='toy-app', raise_error=True, verbose=False)
2941+
29292942
def test_toy_modaltsoftname(self):
29302943
"""Build two dependent toys as in test_toy_toy but using modaltsoftname"""
29312944
topdir = os.path.dirname(os.path.abspath(__file__))

0 commit comments

Comments
 (0)