Skip to content

Commit 6644182

Browse files
authored
Merge pull request #2753 from jfgrimm/20220623114136_new_pr_openblas
add support for iterative build of OpenBLAS with 64-bit integers
2 parents edbd1c1 + dfe796a commit 6644182

File tree

1 file changed

+84
-8
lines changed

1 file changed

+84
-8
lines changed

easybuild/easyblocks/o/openblas.py

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
@author: Andrew Edmondson (University of Birmingham)
55
@author: Alex Domingo (Vrije Universiteit Brussel)
6+
@author: Jasper Grimm (University of York)
67
@author: Kenneth Hoste (Ghent University)
78
"""
89
import os
@@ -12,6 +13,7 @@
1213
from easybuild.framework.easyconfig import CUSTOM
1314
from easybuild.tools.build_log import EasyBuildError, print_warning
1415
from easybuild.tools.config import build_option
16+
from easybuild.tools.filetools import apply_regex_substitutions
1517
from easybuild.tools.run import run_shell_cmd
1618
from easybuild.tools.systemtools import AARCH64, POWER, get_cpu_architecture, get_shared_lib_ext
1719
from easybuild.tools.toolchain.compiler import OPTARCH_GENERIC
@@ -28,6 +30,9 @@ class EB_OpenBLAS(ConfigureMake):
2830
def extra_options():
2931
"""Custom easyconfig parameters for OpenBLAS easyblock."""
3032
extra_vars = {
33+
'enable_ilp64': [True, "Also build OpenBLAS with 64-bit integer support", CUSTOM],
34+
'ilp64_lib_suffix': ['64', "Library name suffix to use when building with 64-bit integers", CUSTOM],
35+
'ilp64_symbol_suffix': ['64_', "Symbol suffix to use when building with 64-bit integers", CUSTOM],
3136
'max_failing_lapack_tests_num_errors': [0, "Maximum number of LAPACK tests failing "
3237
"due to numerical errors", CUSTOM],
3338
'max_failing_lapack_tests_other_errors': [0, "Maximum number of LAPACK tests failing "
@@ -38,9 +43,27 @@ def extra_options():
3843

3944
return ConfigureMake.extra_options(extra_vars)
4045

46+
def __init__(self, *args, **kwargs):
47+
""" Ensure iterative build if also building with 64-bit integer support """
48+
super(EB_OpenBLAS, self).__init__(*args, **kwargs)
49+
50+
if self.cfg['enable_ilp64']:
51+
if not isinstance(self.cfg['buildopts'], list):
52+
niter = 1 + sum([bool(self.cfg[x]) for x in ['ilp64_lib_suffix', 'ilp64_symbol_suffix']])
53+
# ensure iterative build by duplicating buildopts
54+
self.cfg['buildopts'] = [self.cfg['buildopts']] * niter
55+
else:
56+
print_warning("buildopts cannot be a list when 'enable_ilp64' is enabled; ignoring 'enable_ilp64'")
57+
self.cfg['enable_ilp64'] = False
58+
59+
self.orig_opts = {
60+
'buildopts': '',
61+
'testopts': '',
62+
'installopts': '',
63+
}
64+
4165
def configure_step(self):
4266
""" set up some options - but no configure command to run"""
43-
4467
default_opts = {
4568
'BINARY': '64',
4669
'CC': os.getenv('CC'),
@@ -50,6 +73,26 @@ def configure_step(self):
5073
'USE_THREAD': '1',
5174
}
5275

76+
ilp64_lib_opts = {
77+
'INTERFACE64': '1',
78+
'LIBPREFIX': f"libopenblas{self.cfg['ilp64_lib_suffix']}",
79+
}
80+
ilp64_symbol_opts = {
81+
'INTERFACE64': '1',
82+
'SYMBOLSUFFIX': self.cfg['ilp64_symbol_suffix'],
83+
}
84+
85+
# ensure build/test/install options don't persist between iterations
86+
if self.cfg['enable_ilp64']:
87+
if self.iter_idx > 0:
88+
# reset to original build/test/install options
89+
for key in self.orig_opts.keys():
90+
self.cfg[key] = self.orig_opts[key]
91+
else:
92+
# store original options
93+
for key in self.orig_opts.keys():
94+
self.orig_opts[key] = self.cfg[key]
95+
5396
if '%s=' % TARGET in self.cfg['buildopts']:
5497
# Add any TARGET in buildopts to default_opts, so it is passed to testopts and installopts
5598
for buildopt in self.cfg['buildopts'].split():
@@ -78,10 +121,23 @@ def configure_step(self):
78121
self.log.info("Replaced -mcpu=generic with -mtune=generic in $CFLAGS")
79122
env.setvar('CFLAGS', cflags)
80123

81-
for key in sorted(default_opts.keys()):
124+
all_opts = default_opts.copy()
125+
if self.iter_idx > 0 and self.cfg['enable_ilp64']:
126+
# update build/test/install options for ILP64
127+
if self.cfg['ilp64_lib_suffix'] and self.cfg['ilp64_symbol_suffix']:
128+
if self.iter_idx == 1:
129+
all_opts.update(ilp64_lib_opts)
130+
else:
131+
all_opts.update(ilp64_symbol_opts)
132+
elif self.cfg['ilp64_lib_suffix']:
133+
all_opts.update(ilp64_lib_opts)
134+
elif self.cfg['ilp64_symbol_suffix']:
135+
all_opts.update(ilp64_symbol_opts)
136+
137+
for key in sorted(all_opts.keys()):
82138
for opts_key in ['buildopts', 'testopts', 'installopts']:
83-
if '%s=' % key not in self.cfg[opts_key]:
84-
self.cfg.update(opts_key, "%s='%s'" % (key, default_opts[key]))
139+
if f'{key}=' not in self.cfg[opts_key]:
140+
self.cfg.update(opts_key, f"{key}='{all_opts[key]}'")
85141

86142
self.cfg.update('installopts', 'PREFIX=%s' % self.installdir)
87143

@@ -101,15 +157,27 @@ def build_step(self):
101157
# Pass CFLAGS through command line to avoid redefinitions (issue xianyi/OpenBLAS#818)
102158
cflags = 'CFLAGS'
103159
if os.environ[cflags]:
104-
self.cfg.update('buildopts', "%s='%s'" % (cflags, os.environ[cflags]))
160+
self.cfg.update('buildopts', f"{cflags}='{os.environ[cflags]}'")
105161
del os.environ[cflags]
106-
self.log.info("Environment variable %s unset and passed through command line" % cflags)
162+
self.log.info(f"Environment variable {cflags} unset and passed through command line")
107163

108164
makecmd = f'make {self.parallel_flag}'
109165

110166
cmd = ' '.join([self.cfg['prebuildopts'], makecmd, ' '.join(build_parts), self.cfg['buildopts']])
111167
run_shell_cmd(cmd)
112168

169+
def install_step(self):
170+
"""Fix libsuffix in openblas64.pc if it exists"""
171+
super(EB_OpenBLAS, self).install_step()
172+
if self.iter_idx > 0 and self.cfg['enable_ilp64'] and self.cfg['ilp64_lib_suffix']:
173+
filepath = os.path.join(self.installdir, 'lib', 'pkgconfig', 'openblas64.pc')
174+
if os.path.exists(filepath):
175+
regex_subs = [
176+
(r'^libsuffix=.*$', f"libsuffix={self.cfg['ilp64_lib_suffix']}"),
177+
(r'^Name: openblas$', 'Name: openblas64'),
178+
]
179+
apply_regex_substitutions(filepath, regex_subs, backup=False)
180+
113181
def check_lapack_test_results(self, test_output):
114182
"""Check output of OpenBLAS' LAPACK test suite ('make lapack-test')."""
115183

@@ -155,7 +223,7 @@ def test_step(self):
155223
run_tests += [self.cfg['runtest']]
156224

157225
for runtest in run_tests:
158-
cmd = "%s make %s %s" % (self.cfg['pretestopts'], runtest, self.cfg['testopts'])
226+
cmd = f"{self.cfg['pretestopts']} make {runtest} {self.cfg['testopts']}"
159227
res = run_shell_cmd(cmd)
160228

161229
# Raise an error if any test failed
@@ -170,10 +238,18 @@ def test_step(self):
170238

171239
def sanity_check_step(self):
172240
""" Custom sanity check for OpenBLAS """
241+
shlib_ext = get_shared_lib_ext()
173242
custom_paths = {
174243
'files': ['include/cblas.h', 'include/f77blas.h', 'include/lapacke_config.h', 'include/lapacke.h',
175244
'include/lapacke_mangling.h', 'include/lapacke_utils.h', 'include/openblas_config.h',
176-
'lib/libopenblas.a', 'lib/libopenblas.%s' % get_shared_lib_ext()],
245+
'lib/libopenblas.a', f'lib/libopenblas.{shlib_ext}'],
177246
'dirs': [],
178247
}
248+
if self.cfg['enable_ilp64']:
249+
for suffixtype in 'lib', 'symbol':
250+
filename_suffix = self.cfg[f'ilp64_{suffixtype}_suffix']
251+
if filename_suffix:
252+
custom_paths['files'].extend(f"lib/libopenblas{filename_suffix}.{ext}"
253+
for ext in ['a', shlib_ext])
254+
179255
super().sanity_check_step(custom_paths=custom_paths)

0 commit comments

Comments
 (0)