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"""
89import os
1213from easybuild .framework .easyconfig import CUSTOM
1314from easybuild .tools .build_log import EasyBuildError , print_warning
1415from easybuild .tools .config import build_option
16+ from easybuild .tools .filetools import apply_regex_substitutions
1517from easybuild .tools .run import run_shell_cmd
1618from easybuild .tools .systemtools import AARCH64 , POWER , get_cpu_architecture , get_shared_lib_ext
1719from 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