Skip to content

Commit 43f8fb0

Browse files
authored
Merge pull request #12687 from boegel/check_dep_vars_recent_gcccore
improve check for multi-variant dependencies per generation of easyconfigs (for now, only for 2025a & newer)
2 parents a744968 + 3cfa544 commit 43f8fb0

File tree

1 file changed

+84
-19
lines changed

1 file changed

+84
-19
lines changed

test/easyconfigs/easyconfigs.py

Lines changed: 84 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ def test_deps(self):
362362
def check_dep_vars(self, gen, dep, dep_vars):
363363
"""Check whether available variants of a particular dependency are acceptable or not."""
364364

365+
# short-circuit in case there's only one dependency variant, or none at all
366+
if len(dep_vars) <= 1:
367+
return True
368+
365369
# 'guilty' until proven 'innocent'
366370
res = False
367371

@@ -956,43 +960,104 @@ def get_deps_for(ec):
956960

957961
# some software also follows <year>{a,b} versioning scheme,
958962
# which throws off the pattern matching done below for toolchain versions
959-
false_positives_regex = re.compile('^MATLAB-Engine-20[0-9][0-9][ab]')
963+
false_positives_regex = re.compile(r'^MATLAB(-Engine)?-20[0-9][0-9][ab]')
964+
965+
# map GCC(core) version to toolchain generations;
966+
# only for recent generations, where we want to limit dependency variants as much as possible
967+
# across all easyconfigs of that generation (regardless of whether a full toolchain or subtoolchain is used);
968+
# see https://docs.easybuild.io/common-toolchains/#common_toolchains_overview
969+
gcc_tc_gen_map = {
970+
'6.4': '2018a',
971+
'7.3': '2018b',
972+
'8.2': '2019a',
973+
'8.3': '2019b',
974+
'9.3': '2020a',
975+
'10.2': '2020b',
976+
'10.3': '2021a',
977+
'11.1': None,
978+
'11.2': '2021b',
979+
'11.3': '2022a',
980+
'11.4': None,
981+
'12.1': None,
982+
'12.2': '2022b',
983+
'12.3': '2023a',
984+
'13.1': None,
985+
'13.1': None,
986+
'13.2': '2023b',
987+
'13.3': '2024a',
988+
'14.1': None,
989+
'14.2': '2025a',
990+
'14.3': '2025b',
991+
'15.1': None,
992+
}
960993

961994
multi_dep_vars_msg = ''
962-
# restrict to checking dependencies of easyconfigs using common toolchains (start with 2018a)
963-
# and GCCcore subtoolchain for common toolchains, starting with GCCcore 7.x
964-
for pattern in ['20(1[89]|[2-9][0-9])[ab]', r'GCCcore-([7-9]|[1-9][0-9])\.[0-9]']:
965-
all_deps = {}
966-
regex = re.compile(r'^.*-(?P<tc_gen>%s).*\.eb$' % pattern)
995+
# restrict to checking dependencies of easyconfigs using common toolchains,
996+
# and GCCcore subtoolchain for common toolchains;
997+
# for now, we only enforce this for recent toolchain versions (2025a + GCCcore 14.x, and newer);
998+
patterns = [
999+
# compiler-only subtoolchains GCCcore and GCC
1000+
# r'GCCcore-[7-9]\.[0-9]\.',
1001+
# r'GCC(core)?-1[0-9]\.[0-9]\.', # GCCcore 10.x, etc.
1002+
r'GCC(core)?-1[4-9]\.[0-9]\.', # GCCcore 14.x & newer
1003+
# only check GCC 9.x toolchains, not older GCC versions
1004+
# (we started checking dependency variants too late for GCC 8.x and older)
1005+
# r'GCC-9\.[0-9]\.',
1006+
# full toolchains, like foss/2019b or intel/2020a
1007+
# r'(201[89]|20[2-9][0-9])[ab]',
1008+
r'(202[5-9]|20[3-9][0-9])[ab]', # 2025a and newer
1009+
]
1010+
1011+
all_deps = {}
1012+
1013+
# collect variants for all dependencies of easyconfigs that use a toolchain that matches
1014+
for ec in self.ordered_specs:
1015+
ec_file = os.path.basename(ec['spec'])
1016+
ec_deps = None
9671017

968-
# collect variants for all dependencies of easyconfigs that use a toolchain that matches
969-
for ec in self.ordered_specs:
970-
ec_file = os.path.basename(ec['spec'])
1018+
for pattern in patterns:
1019+
regex = re.compile(r'^.*-(?P<tc_gen>%s).*\.eb$' % pattern)
9711020

9721021
# take into account software which also follows a <year>{a,b} versioning scheme
9731022
ec_file = false_positives_regex.sub('', ec_file)
9741023

9751024
res = regex.match(ec_file)
9761025
if res:
9771026
tc_gen = res.group('tc_gen')
1027+
1028+
if tc_gen.startswith('GCC'):
1029+
gcc_ver = tc_gen.split('-', 1)[1].rstrip('.')
1030+
if gcc_ver in gcc_tc_gen_map and gcc_tc_gen_map[gcc_ver] is not None:
1031+
tc_gen = gcc_tc_gen_map[gcc_ver]
1032+
elif LooseVersion(gcc_ver) >= LooseVersion('10.2') and gcc_ver not in gcc_tc_gen_map:
1033+
# for recent GCC versions, we really want to have a mapping in place...
1034+
self.fail("No mapping for GCC(core) %s to toolchain generation!" % gcc_ver)
1035+
1036+
if ec_deps is None:
1037+
ec_deps = get_deps_for(ec)
1038+
9781039
all_deps_tc_gen = all_deps.setdefault(tc_gen, {})
979-
for dep_name, dep_ver, dep_versuff, dep_mod_name in get_deps_for(ec):
1040+
for dep_name, dep_ver, dep_versuff, _ in ec_deps:
9801041
dep_variants = all_deps_tc_gen.setdefault(dep_name, {})
9811042
# a variant is defined by version + versionsuffix
9821043
variant = "version: %s; versionsuffix: %s" % (dep_ver, dep_versuff)
9831044
# keep track of which easyconfig this is a dependency
9841045
dep_variants.setdefault(variant, set()).add(ec_file)
9851046

986-
# check which dependencies have more than 1 variant
987-
for tc_gen, deps in sorted(all_deps.items()):
988-
for dep, dep_vars in sorted(deps.items()):
989-
if not self.check_dep_vars(tc_gen, dep, dep_vars):
990-
multi_dep_vars_msg += "Found %s variants of '%s' dependency " % (len(dep_vars), dep)
991-
multi_dep_vars_msg += "in easyconfigs using '%s' toolchain generation\n* " % tc_gen
992-
multi_dep_vars_msg += '\n * '.join("%s as dep for %s" % v for v in sorted(dep_vars.items()))
993-
multi_dep_vars_msg += '\n'
1047+
# check which dependencies have more than 1 variant
1048+
multi_dep_vars, multi_dep_vars_msg = [], ''
1049+
for tc_gen in sorted(all_deps.keys()):
1050+
for dep in sorted(all_deps[tc_gen].keys()):
1051+
dep_vars = all_deps[tc_gen][dep]
1052+
if not self.check_dep_vars(tc_gen, dep, dep_vars):
1053+
multi_dep_vars.append(dep)
1054+
multi_dep_vars_msg += "\nfound %s variants of '%s' dependency " % (len(dep_vars), dep)
1055+
multi_dep_vars_msg += "in easyconfigs using '%s' toolchain generation\n* " % tc_gen
1056+
multi_dep_vars_msg += '\n* '.join("%s as dep for %s" % v for v in sorted(dep_vars.items()))
1057+
multi_dep_vars_msg += '\n'
1058+
9941059
if multi_dep_vars_msg:
995-
self.fail('Should not have multiple variants of dependencies.\n' + multi_dep_vars_msg)
1060+
self.fail("Should not have multi-variant dependencies in easyconfigs:\n%s" % multi_dep_vars_msg)
9961061

9971062
def test_downloadable_or_instructions(self):
9981063
"""

0 commit comments

Comments
 (0)