Skip to content

Commit b07033b

Browse files
authored
Merge pull request #4699 from Flamefire/fullpath-libdir
enhance `get_software_libdir` to return full paths if requested
2 parents ede3568 + f35ae5e commit b07033b

File tree

2 files changed

+66
-49
lines changed

2 files changed

+66
-49
lines changed

easybuild/tools/modules.py

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,7 +1697,7 @@ def get_software_root(name, with_env_var=False):
16971697
return res
16981698

16991699

1700-
def get_software_libdir(name, only_one=True, fs=None):
1700+
def get_software_libdir(name, only_one=True, fs=None, full_path=False):
17011701
"""
17021702
Find library subdirectories for the specified software package.
17031703
@@ -1708,51 +1708,57 @@ def get_software_libdir(name, only_one=True, fs=None):
17081708
:param name: name of the software package
17091709
:param only_one: indicates whether only one lib path is expected to be found
17101710
:param fs: only retain library subdirs that contain one of the files in this list
1711+
:param full_path: Include the software root in the returned path, or just return the subfolder found
17111712
"""
17121713
lib_subdirs = ['lib', 'lib64']
17131714
root = get_software_root(name)
1714-
res = []
1715-
if root:
1716-
for lib_subdir in lib_subdirs:
1717-
lib_dir_path = os.path.join(root, lib_subdir)
1718-
if os.path.exists(lib_dir_path):
1719-
# take into account that lib64 could be a symlink to lib (or vice versa)
1720-
# see https://github.com/easybuilders/easybuild-framework/issues/3139
1721-
if any(os.path.samefile(lib_dir_path, os.path.join(root, x)) for x in res):
1722-
_log.debug("%s is the same as one of the other paths, so skipping it", lib_dir_path)
1723-
1724-
elif fs is None or any(os.path.exists(os.path.join(lib_dir_path, f)) for f in fs):
1725-
_log.debug("Retaining library subdir '%s' (found at %s)", lib_subdir, lib_dir_path)
1726-
res.append(lib_subdir)
1727-
1728-
elif build_option('extended_dry_run'):
1729-
res.append(lib_subdir)
1730-
break
1731-
1732-
# if no library subdir was found, return None
1733-
if not res:
1734-
return None
1735-
if only_one:
1736-
if len(res) == 1:
1737-
res = res[0]
1738-
else:
1739-
if fs is None and len(res) == 2:
1740-
# if both lib and lib64 were found, check if only one (exactly) has libraries;
1741-
# this is needed for software with library archives in lib64 but other files/directories in lib
1742-
lib_glob = ['*.%s' % ext for ext in ['a', get_shared_lib_ext()]]
1743-
has_libs = [any(glob.glob(os.path.join(root, subdir, f)) for f in lib_glob) for subdir in res]
1744-
if has_libs[0] and not has_libs[1]:
1745-
return res[0]
1746-
elif has_libs[1] and not has_libs[0]:
1747-
return res[1]
1748-
1749-
raise EasyBuildError("Multiple library subdirectories found for %s in %s: %s",
1750-
name, root, ', '.join(res))
1751-
return res
1752-
else:
1715+
if not root:
17531716
# return None if software package root could not be determined
17541717
return None
17551718

1719+
found_subdirs = []
1720+
for lib_subdir in lib_subdirs:
1721+
lib_dir_path = os.path.join(root, lib_subdir)
1722+
if os.path.exists(lib_dir_path):
1723+
# take into account that lib64 could be a symlink to lib (or vice versa)
1724+
# see https://github.com/easybuilders/easybuild-framework/issues/3139
1725+
if any(os.path.samefile(lib_dir_path, os.path.join(root, x)) for x in found_subdirs):
1726+
_log.debug("%s is the same as one of the other paths, so skipping it", lib_dir_path)
1727+
1728+
elif fs is None or any(os.path.exists(os.path.join(lib_dir_path, f)) for f in fs):
1729+
_log.debug("Retaining library subdir '%s' (found at %s)", lib_subdir, lib_dir_path)
1730+
found_subdirs.append(lib_subdir)
1731+
1732+
elif build_option('extended_dry_run'):
1733+
found_subdirs.append(lib_subdir)
1734+
break
1735+
1736+
# if no library subdir was found, return None
1737+
if not found_subdirs:
1738+
return None
1739+
if full_path:
1740+
res = [os.path.join(root, subdir) for subdir in found_subdirs]
1741+
else:
1742+
res = found_subdirs
1743+
if only_one:
1744+
if len(res) == 1:
1745+
res = res[0]
1746+
else:
1747+
if fs is None and len(res) == 2:
1748+
# if both lib and lib64 were found, check if only one (exactly) has libraries;
1749+
# this is needed for software with library archives in lib64 but other files/directories in lib
1750+
lib_glob = ['*.%s' % ext for ext in ['a', get_shared_lib_ext()]]
1751+
has_libs = [any(glob.glob(os.path.join(root, subdir, f)) for f in lib_glob)
1752+
for subdir in found_subdirs]
1753+
if has_libs[0] and not has_libs[1]:
1754+
return res[0]
1755+
if has_libs[1] and not has_libs[0]:
1756+
return res[1]
1757+
1758+
raise EasyBuildError("Multiple library subdirectories found for %s in %s: %s",
1759+
name, root, ', '.join(found_subdirs))
1760+
return res
1761+
17561762

17571763
def get_software_version_env_var_name(name):
17581764
"""Return name of environment variable for software root."""

test/framework/modules.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ def test_get_software_root_version_libdir(self):
686686
self.assertEqual(get_software_root(name), root)
687687
self.assertEqual(get_software_version(name), version)
688688
self.assertEqual(get_software_libdir(name), 'lib')
689+
self.assertEqual(get_software_libdir(name, full_path=True), os.path.join(root, 'lib'))
689690

690691
os.environ.pop('EBROOT%s' % env_var_name)
691692
os.environ.pop('EBVERSION%s' % env_var_name)
@@ -694,50 +695,60 @@ def test_get_software_root_version_libdir(self):
694695
root = os.path.join(tmpdir, name)
695696
mkdir(os.path.join(root, 'lib64'))
696697
os.environ['EBROOT%s' % env_var_name] = root
698+
699+
def check_get_software_libdir(expected, **additional_args):
700+
self.assertEqual(get_software_libdir(name, **additional_args), expected)
701+
if isinstance(expected, list):
702+
expected = [os.path.join(root, d) for d in expected]
703+
elif expected:
704+
expected = os.path.join(root, expected)
705+
self.assertEqual(get_software_libdir(name, full_path=True, **additional_args), expected)
706+
697707
write_file(os.path.join(root, 'lib', 'libfoo.a'), 'foo')
698-
self.assertEqual(get_software_libdir(name), 'lib')
708+
check_get_software_libdir('lib')
699709

700710
remove_file(os.path.join(root, 'lib', 'libfoo.a'))
701711

702712
# also check vice versa with *shared* library in lib64
703713
shlib_ext = get_shared_lib_ext()
704714
write_file(os.path.join(root, 'lib64', 'libfoo.' + shlib_ext), 'foo')
705-
self.assertEqual(get_software_libdir(name), 'lib64')
715+
check_get_software_libdir('lib64')
706716

707717
remove_file(os.path.join(root, 'lib64', 'libfoo.' + shlib_ext))
708718

709719
# check expected result of get_software_libdir with multiple lib subdirs
710720
self.assertErrorRegex(EasyBuildError, "Multiple library subdirectories found.*", get_software_libdir, name)
711-
self.assertEqual(get_software_libdir(name, only_one=False), ['lib', 'lib64'])
721+
check_get_software_libdir(only_one=False, expected=['lib', 'lib64'])
712722

713723
# only directories containing files in specified list should be retained
714724
write_file(os.path.join(root, 'lib64', 'foo'), 'foo')
715-
self.assertEqual(get_software_libdir(name, fs=['foo']), 'lib64')
725+
check_get_software_libdir(fs=['foo'], expected='lib64')
716726

717727
# duplicate paths due to symlink get filtered
718728
remove_dir(os.path.join(root, 'lib64'))
719729
symlink(os.path.join(root, 'lib'), os.path.join(root, 'lib64'))
720-
self.assertEqual(get_software_libdir(name), 'lib')
730+
check_get_software_libdir('lib')
721731

722732
# same goes for lib symlinked to lib64
723733
remove_file(os.path.join(root, 'lib64'))
724734
remove_dir(os.path.join(root, 'lib'))
725735
mkdir(os.path.join(root, 'lib64'))
726736
symlink(os.path.join(root, 'lib64'), os.path.join(root, 'lib'))
727737
# still returns 'lib' because that's the first subdir considered
728-
self.assertEqual(get_software_libdir(name), 'lib')
738+
check_get_software_libdir('lib')
729739

730740
# clean up for previous tests
731741
os.environ.pop('EBROOT%s' % env_var_name)
732742

733743
# if root/version for specified software package can not be found, these functions should return None
734-
self.assertEqual(get_software_root('foo'), None)
735-
self.assertEqual(get_software_version('foo'), None)
736-
self.assertEqual(get_software_libdir('foo'), None)
744+
self.assertEqual(get_software_root(name), None)
745+
self.assertEqual(get_software_version(name), None)
746+
check_get_software_libdir(None)
737747

738748
# if no library subdir is found, get_software_libdir should return None
739749
os.environ['EBROOTFOO'] = tmpdir
740750
self.assertEqual(get_software_libdir('foo'), None)
751+
self.assertEqual(get_software_libdir('foo', full_path=True), None)
741752
os.environ.pop('EBROOTFOO')
742753

743754
shutil.rmtree(tmpdir)

0 commit comments

Comments
 (0)