1from __future__ import generators 2import config.base 3import config.package 4from sourceDatabase import SourceDB 5import os 6 7class Configure(config.package.Package): 8 def __init__(self, framework): 9 config.package.Package.__init__(self, framework) 10 self.defaultPrecision = 'double' 11 self.f2c = 0 # indicates either the f2cblaslapack are used or there is no Fortran compiler (and system BLAS/LAPACK is used) 12 self.has64bitindices = 0 13 self.mkl = 0 # indicates BLAS/LAPACK library used is Intel MKL 14 self.mkl_spblas_h = 0 # indicates mkl_spblas.h is found 15 self.separateBlas = 1 16 self.required = 1 17 self.alternativedownload = 'f2cblaslapack' 18 self.mangling = 'unknown' 19 self.missingRoutines = [] 20 self.libDirs = [os.path.join('lib','64'),os.path.join('lib','ia64'),os.path.join('lib','em64t'),os.path.join('lib','intel64'),'lib','64',\ 21 'ia64','em64t','intel64', os.path.join('lib','32'),os.path.join('lib','ia32'),'32','ia32',''] 22 23 def setupDependencies(self, framework): 24 config.package.Package.setupDependencies(self, framework) 25 self.f2cblaslapack = framework.require('config.packages.f2cblaslapack', self) 26 self.netliblapack = framework.require('config.packages.netlib-lapack', self) 27 self.fblaslapack = framework.require('config.packages.fblaslapack', self) 28 self.libflame = framework.require('config.packages.libflame', self) 29 self.blis = framework.require('config.packages.BLIS', self) 30 self.openblas = framework.require('config.packages.OpenBLAS', self) 31 self.flibs = framework.require('config.packages.flibs',self) 32 self.mathlib = framework.require('config.packages.mathlib',self) 33 self.openmp = framework.require('config.packages.OpenMP',self) 34 self.mpi = framework.require('config.packages.MPI',self) 35 self.deps = [self.flibs,self.mathlib] 36 self.odeps = [self.mpi] 37 return 38 39 def __str__(self): 40 output = config.package.Package.__str__(self) 41 if self.has64bitindices: 42 output += ' uses 8 byte integers\n' 43 else: 44 output += ' uses 4 byte integers\n' 45 return output 46 47 def setupHelp(self, help): 48 config.package.Package.setupHelp(self,help) 49 import nargs 50 help.addArgument('BLAS/LAPACK', '-with-blas-lib=<libraries: e.g. [/Users/..../libblas.a,...]>', nargs.ArgLibrary(None, None, 'Indicate the library(s) containing BLAS')) 51 help.addArgument('BLAS/LAPACK', '-with-lapack-lib=<libraries: e.g. [/Users/..../liblapack.a,...]>',nargs.ArgLibrary(None, None, 'Indicate the library(s) containing LAPACK')) 52 help.addArgument('BLAS/LAPACK', '-with-blaslapack-suffix=<string>',nargs.Arg(None, None, 'Indicate a suffix for BLAS/LAPACK subroutine names.')) 53 help.addArgument('BLAS/LAPACK', '-with-64-bit-blas-indices', nargs.ArgBool(None, 0, 'Try to use 64-bit integers for BLAS/LAPACK; will error if not available')) 54 help.addArgument('BLAS/LAPACK', '-known-blaslapack-mangling=<string>', nargs.ArgString(None, None, 'Indicate known name mangling for BLAS/LAPACK subroutine names (unchanged, underscore, caps)', regExp='^(unchanged|underscore|caps)$')) 55 help.addArgument('BLAS/LAPACK', '-known-blaslapack-openmp=<bool>', nargs.ArgBool(None, None, 'Indicate if BLAS/LAPACK uses OpenMP')) 56 help.addArgument('BLAS/LAPACK', '-known-64-bit-blas-indices=<bool>', nargs.ArgBool(None, None, 'Indicate if BLAS/LAPACK uses 64 bit integers\n Should be used only when the auto-detection of 64 bit integers in BLAS/LAPACK fails')) 57 help.addArgument('BLAS/LAPACK', '-known-snrm2-returns-double=<bool>', nargs.ArgBool(None, None, 'Indicate if BLAS snrm2() returns a double')) 58 help.addArgument('BLAS/LAPACK', '-known-sdot-returns-double=<bool>', nargs.ArgBool(None, None, 'Indicate if BLAS sdot() returns a double')) 59 return 60 61 def getPrefix(self): 62 if self.compilers.fortranMangling == 'caps': 63 if self.defaultPrecision == 'single': return 'S' 64 if self.defaultPrecision == 'double': return 'D' 65 if self.defaultPrecision == '__float128': return 'Q' 66 if self.defaultPrecision == '__fp16': return 'H' 67 return 'Unknown precision' 68 else: 69 if self.defaultPrecision == 'single': return 's' 70 if self.defaultPrecision == 'double': return 'd' 71 if self.defaultPrecision == '__float128': return 'q' 72 if self.defaultPrecision == '__fp16': return 'h' 73 return 'Unknown precision' 74 75 def getType(self): 76 if self.defaultPrecision == 'single': return 'float' 77 return self.defaultPrecision 78 79 def getOtherLibs(self, foundBlas = None, blasLibrary = None, separateBlas = None): 80 if foundBlas is None: 81 foundBlas = getattr(self, "foundBlas", None) 82 if blasLibrary is None: 83 blasLibrary = getattr(self, "blasLibrary", None) 84 if separateBlas is None: 85 separateBlas = getattr(self, "separateBlas", None) 86 otherLibs = [] 87 if foundBlas and separateBlas and blasLibrary: 88 otherLibs += blasLibrary 89 otherLibs += self.dlib 90 return otherLibs 91 92 def checkBlas(self, blasLibrary, otherLibs, mangling = None, routinesIn = ['dot']): 93 '''This checks the given library for the routine, dot by default''' 94 oldLibs = self.compilers.LIBS 95 if not isinstance(routinesIn, list): 96 routinesIn = [routinesIn] 97 routines = map(self.mangleBlas, routinesIn, [mangling]*len(routinesIn)) 98 _, missing = self.libraries.checkClassify(blasLibrary, routines, otherLibs = otherLibs) 99 self.compilers.LIBS = oldLibs 100 return len(missing) == 0, missing 101 102 def checkLapack(self, lapackLibrary, otherLibs, mangling = None, routinesIn = ['getrs','geev']): 103 oldLibs = self.compilers.LIBS 104 if not isinstance(routinesIn, list): 105 routinesIn = [routinesIn] 106 routines = map(self.mangleBlas, routinesIn, [mangling]*len(routinesIn)) 107 _, missing = self.libraries.checkClassify(lapackLibrary, routines, otherLibs = otherLibs) 108 self.compilers.LIBS = oldLibs 109 return len(missing) == 0, missing 110 111 def checkBlasMangling(self, mangling, lapackLibrary, blasLibrary = None): 112 foundBlas, missingBlas = self.checkBlas(blasLibrary, self.getOtherLibs(), mangling, ['dot']) 113 foundLapack, missingLapack = self.checkLapack(lapackLibrary, self.getOtherLibs(foundBlas, blasLibrary), mangling, ['getrs','geev']) 114 if foundBlas and foundLapack: 115 self.logPrint('Found mangling on BLAS/LAPACK: '+mangling) 116 return (foundBlas, missingBlas, foundLapack, missingLapack) 117 118 def checkLib(self, lapackLibrary, blasLibrary = None): 119 '''Checking for BLAS and LAPACK symbols''' 120 if blasLibrary is None: 121 self.separateBlas = 0 122 blasLibrary = lapackLibrary 123 else: 124 self.separateBlas = 1 125 if not isinstance(lapackLibrary, list): 126 lapackLibrary = [lapackLibrary] 127 if not isinstance(blasLibrary, list): 128 blasLibrary = [blasLibrary] 129 130 # allow a user-specified suffix to be appended to BLAS/LAPACK symbols 131 self.suffix = self.argDB.get('with-blaslapack-suffix', '') 132 # allow user to dictate which BLAS/LAPACK mangling to use (some BLAS/LAPACK libraries, like on Apple, provide several) 133 if 'known-blaslapack-mangling' in self.argDB: 134 mangling = self.argDB['known-blaslapack-mangling'] 135 # check user-provided mangling, return the result regardless of success (errors are handled elsewhere) 136 (foundBlas, missingBlas, foundLapack, missingLapack) = self.checkBlasMangling(mangling, lapackLibrary, blasLibrary) 137 self.mangling = mangling 138 return (foundBlas, foundLapack) 139 140 manglings = ['unchanged', 'underscore', 'caps'] 141 # if we have a Fortran compiler, check that mangling first 142 if hasattr(self.compilers, 'FC'): 143 mangling = self.compilers.fortranMangling 144 self.logPrint('Checking for Fortran name mangling "'+mangling+'" on BLAS/LAPACK') 145 (foundBlas, missingBlas, foundLapack, missingLapack) = self.checkBlasMangling(mangling, lapackLibrary, blasLibrary) 146 if not foundBlas: 147 self.logPrint('BLAS does not use Fortran name mangling "'+mangling+'", missing '+str(missingBlas)) 148 if not foundLapack: 149 self.logPrint('LAPACK does not use Fortran name mangling "'+mangling+'", missing '+str(missingLapack)) 150 if foundBlas and foundLapack: 151 self.logPrint('Found Fortran name mangling "'+mangling+'" on BLAS/LAPACK') 152 self.mangling = mangling 153 return (foundBlas, foundLapack) 154 if mangling in manglings: 155 manglings.remove(mangling) 156 157 for mangling in manglings: 158 self.logPrint('Checking for "'+mangling+'" name mangling on BLAS/LAPACK') 159 (foundBlas, missingBlas, foundLapack, missingLapack) = self.checkBlasMangling(mangling, lapackLibrary, blasLibrary) 160 if not foundBlas: 161 self.logPrint('BLAS does not use "'+mangling+'" name mangling, missing '+str(missingBlas)) 162 if not foundLapack: 163 self.logPrint('LAPACK does not use "'+mangling+'" name mangling, missing '+str(missingLapack)) 164 if foundBlas and foundLapack: 165 self.logPrint('Found "'+mangling+'" name mangling on BLAS/LAPACK') 166 self.mangling = mangling 167 return (foundBlas, foundLapack) 168 169 self.logPrint('Unknown name mangling in BLAS/LAPACK') 170 self.mangling = 'unknown' 171 return (False, False) 172 173 def generateGuesses(self): 174 # check that user has used the options properly 175 if 'with-blas-lib' in self.argDB and not 'with-lapack-lib' in self.argDB: 176 raise RuntimeError('If you use the --with-blas-lib=<lib> you must also use --with-lapack-lib=<lib> option') 177 if not 'with-blas-lib' in self.argDB and 'with-lapack-lib' in self.argDB: 178 raise RuntimeError('If you use the --with-lapack-lib=<lib> you must also use --with-blas-lib=<lib> option') 179 if 'with-blas-lib' in self.argDB and 'with-blaslapack-dir' in self.argDB: 180 raise RuntimeError('You cannot set both the library containing BLAS with --with-blas-lib=<lib>\nand the directory to search with --with-blaslapack-dir=<dir>') 181 if 'with-blaslapack-lib' in self.argDB and 'with-blaslapack-dir' in self.argDB: 182 raise RuntimeError('You cannot set both the library containing BLAS/LAPACK with --with-blaslapack-lib=<lib>\nand the directory to search with --with-blaslapack-dir=<dir>') 183 184 # Try specified BLAS/LAPACK library 185 if 'with-blaslapack-lib' in self.argDB: 186 if 'known-64-bit-blas-indices' in self.argDB: 187 if self.argDB['known-64-bit-blas-indices']: 188 known_64bit = '64' 189 else: 190 known_64bit = '32' 191 else: 192 known_64bit = 'unknown' 193 if 'known-blas-openmp' in self.argDB: 194 if self.argDB['known-blas-openmp']: 195 known_openmp = 'yes' 196 else: 197 known_openmp = 'no' 198 else: 199 known_openmp = 'unknown' 200 yield ('User specified BLAS/LAPACK library', None, self.argDB['with-blaslapack-lib'], known_64bit, known_openmp) 201 # add warning for user-specified mangling 202 warn_known_mangling = "" 203 if 'known-blaslapack-mangling' in self.argDB: 204 warn_known_mangling = 'Try running without --known-blaslapack-mangling='+self.argDB['known-blaslapack-mangling']+' to try to identify mangled names automatically\n' 205 if self.defaultPrecision == '__float128': 206 raise RuntimeError('__float128 precision requires f2c BLAS/LAPACK libraries; they are not available in '+str(self.argDB['with-blaslapack-lib'])+'; suggest --download-f2cblaslapack\n'+warn_known_mangling) 207 else: 208 raise RuntimeError('You set a value for --with-blaslapack-lib=<lib>, but '+str(self.argDB['with-blaslapack-lib'])+' cannot be used\n'+warn_known_mangling) 209 # Try specified BLAS and LAPACK libraries 210 if 'with-blas-lib' in self.argDB and 'with-lapack-lib' in self.argDB: 211 if 'known-64-bit-blas-indices' in self.argDB: 212 if self.argDB['known-64-bit-blas-indices']: 213 known_64bit = '64' 214 else: 215 known_64bit = '32' 216 else: 217 known_64bit = 'unknown' 218 if 'known-blas-openmp' in self.argDB: 219 if self.argDB['known-blas-openmp']: 220 known_openmp = 'yes' 221 else: 222 known_openmp = 'no' 223 else: 224 known_openmp = 'unknown' 225 yield ('User specified BLAS and LAPACK libraries', self.argDB['with-blas-lib'], self.argDB['with-lapack-lib'], known_64bit, known_openmp) 226 # add warning for user-specified mangling 227 warn_known_mangling = "" 228 if 'known-blaslapack-mangling' in self.argDB: 229 warn_known_mangling = 'Try running without --known-blaslapack-mangling='+self.argDB['known-blaslapack-mangling']+' to try to identify mangled names automatically\n' 230 if self.defaultPrecision == '__float128': 231 raise RuntimeError('__float128 precision requires f2c BLAS/LAPACK libraries; they are not available in '+str(self.argDB['with-blas-lib'])+' and '+str(self.argDB['with-lapack-lib'])+'; suggest --download-f2cblaslapack\n'+warn_known_mangling) 232 else: 233 raise RuntimeError('You set a value for --with-blas-lib=<lib> and --with-lapack-lib=<lib>, but '+str(self.argDB['with-blas-lib'])+' and '+str(self.argDB['with-lapack-lib'])+' cannot be used\n'+warn_known_mangling) 234 235 if self.f2cblaslapack.found: 236 self.f2c = 1 237 # TODO: use self.f2cblaslapack.libDir directly 238 libDir = os.path.join(self.f2cblaslapack.directory,'lib') 239 f2cBlas = [os.path.join(libDir,'libf2cblas.a')] 240 if self.blis.found: 241 # The real BLAS is provided by libblis, but we still need libf2cblas for aux functions needed by libf2clapack 242 f2cBlas += self.blis.lib 243 f2cLapack = [os.path.join(libDir,'libf2clapack.a')] 244 yield ('f2cblaslapack', f2cBlas, f2cLapack, '32','no') 245 yield ('f2cblaslapack', f2cBlas+['-lquadmath'], f2cLapack, '32','no') 246 raise RuntimeError('--download-f2cblaslapack libraries cannot be used') 247 if self.netliblapack.found: 248 self.f2c = 0 249 # TODO: use self.netliblapack.libDir directly 250 libDir = os.path.join(self.netliblapack.directory,'lib') 251 if self.netliblapack.cinterface: 252 yield ('netliblapack', [os.path.join(libDir,'libcblas.a'), os.path.join(libDir,'libblas.a')], [os.path.join(libDir,'liblapacke.a'), os.path.join(libDir,'liblapack.a')], '32', 'no') 253 else: 254 yield ('netliblapack', [os.path.join(libDir,'libnblas.a')], [os.path.join(libDir,'libnlapack.a')], '32', 'no') 255 raise RuntimeError('--download-netlib-lapack libraries cannot be used') 256 if self.fblaslapack.found: 257 self.f2c = 0 258 # TODO: use self.fblaslapack.libDir directly 259 libDir = os.path.join(self.fblaslapack.directory,'lib') 260 yield ('fblaslapack', os.path.join(libDir,'libfblas.a'), os.path.join(libDir,'libflapack.a'), '32','no') 261 raise RuntimeError('--download-fblaslapack libraries cannot be used') 262 if self.libflame.found: 263 self.f2c = 0 264 # TODO: use self.libflame.libDir directly 265 libDir = os.path.join(self.libflame.directory,'lib') 266 yield ('libflame', self.blis.lib, os.path.join(libDir,'libflame.a'), self.blis.known64, self.blis.usesopenmp) 267 raise RuntimeError('--download-libflame libraries cannot be used') 268 if self.blis.found: 269 self.f2c = 0 270 # TODO: Where shall we find liblapack.a? 271 yield ('BLIS', self.blis.lib, 'liblapack.a', self.blis.known64, self.blis.usesopenmp) 272 if self.openblas.found: 273 self.f2c = 0 274 self.include = self.openblas.include 275 if self.openblas.libDir: 276 yield ('OpenBLAS with full path', None, os.path.join(self.openblas.libDir,'libopenblas.a'),self.openblas.known64,self.openblas.usesopenmp) 277 else: 278 yield ('OpenBLAS', None, self.openblas.lib,self.openblas.known64,self.openblas.usesopenmp) 279 raise RuntimeError('--download-openblas libraries cannot be used') 280 281 blislib = ['libblis.a'] 282 if self.openmp.found: 283 blislib.insert(0,'libblis-mt.a') 284 285 if not 'with-blaslapack-dir' in self.argDB: 286 mkl = os.getenv('MKLROOT') 287 if mkl: 288 # Since user did not select MKL specifically first try compiler defaults and only if they fail use the MKL 289 yield ('Default compiler libraries', '', '','unknown','unknown') 290 for lib in blislib: 291 for lapack in ['libflame.a','liblapack.a']: 292 for libdir in ['',os.path.join('/usr','local','lib')]: 293 if libdir: 294 lib = os.path.join(libdir,lib) 295 lapack = os.path.join(libdir,lapack) 296 yield ('BLIS/AMD-AOCL default compiler locations '+libdir,lib,lapack,'unknown','unknown') 297 yield ('OpenBLAS default compiler locations', None, 'libopenblas.a','unknown','unknown') 298 yield ('OpenBLAS default compiler locations /usr/local/lib', None, os.path.join('/usr','local','lib','libopenblas.a'),'unknown','unknown') 299 yield ('Default compiler locations', 'libblas.a', 'liblapack.a','unknown','unknown') 300 yield ('Default compiler locations /usr/local/lib', os.path.join('/usr','local','lib','libblas.a'), os.path.join('/usr','local','lib','liblapack.a'),'unknown','unknown') 301 yield ('Default compiler locations with gfortran', None, ['liblapack.a', 'libblas.a','libgfortran.a'],'unknown','unknown') 302 self.logWrite('Did not detect default BLAS and LAPACK locations so using the value of MKLROOT to search as --with-blas-lapack-dir='+mkl) 303 self.argDB['with-blaslapack-dir'] = mkl 304 305 if self.argDB['with-64-bit-blas-indices']: 306 flexiblas = 'libflexiblas64.a' 307 ILP64 = '_ilp64' 308 known = '64' 309 else: 310 flexiblas = 'libflexiblas.a' 311 ILP64 = '_lp64' 312 known = '32' 313 314 if self.openmp.found: 315 ITHREADS=['intel_thread','gnu_thread'] 316 ompthread = 'yes' 317 else: 318 ITHREADS=['sequential'] 319 ompthread = 'no' 320 321 # Try specified installation root 322 if 'with-blaslapack-dir' in self.argDB: 323 dir = self.argDB['with-blaslapack-dir'] 324 # error if package-dir is in externalpackages 325 if os.path.realpath(dir).find(os.path.realpath(self.externalPackagesDir)) >=0: 326 fakeExternalPackagesDir = dir.replace(os.path.realpath(dir).replace(os.path.realpath(self.externalPackagesDir),''),'') 327 raise RuntimeError('Bad option: '+'--with-blaslapack-dir='+self.argDB['with-blaslapack-dir']+'\n'+ 328 fakeExternalPackagesDir+' is reserved for --download-package scratch space. \n'+ 329 'Do not install software in this location nor use software in this directory.') 330 if self.defaultPrecision == '__float128': 331 yield ('User specified installation root (F2CBLASLAPACK)', os.path.join(dir,'libf2cblas.a'), os.path.join(dir, 'libf2clapack.a'), '32','no') 332 raise RuntimeError('__float128 precision requires f2c libraries; they are not available in '+dir+'; suggest --download-f2cblaslapack\n') 333 334 if not (len(dir) > 2 and dir[1] == ':') : 335 dir = os.path.abspath(dir) 336 self.log.write('Looking for BLAS/LAPACK in user specified directory: '+dir+'\n') 337 self.log.write('Files and directories in that directory:\n'+str(os.listdir(dir))+'\n') 338 339 # Look for multi-threaded MKL for MKL_C/Pardiso 340 useCPardiso=0 341 usePardiso=0 342 if self.argDB['with-mkl_cpardiso'] or 'with-mkl_cpardiso-dir' in self.argDB or 'with-mkl_cpardiso-lib' in self.argDB: 343 useCPardiso=1 344 if self.mpi.found and hasattr(self.mpi, 'ompi_major_version'): 345 mkl_blacs_64=[['mkl_blacs_openmpi'+ILP64+'']] 346 mkl_blacs_32=[['mkl_blacs_openmpi']] 347 else: 348 mkl_blacs_64=[['mkl_blacs_intelmpi'+ILP64+''],['mkl_blacs_mpich'+ILP64+''],['mkl_blacs_sgimpt'+ILP64+''],['mkl_blacs_openmpi'+ILP64+'']] 349 mkl_blacs_32=[['mkl_blacs_intelmpi'],['mkl_blacs_mpich'],['mkl_blacs_sgimpt'],['mkl_blacs_openmpi']] 350 elif self.argDB['with-mkl_pardiso'] or 'with-mkl_pardiso-dir' in self.argDB or 'with-mkl_pardiso-lib' in self.argDB: 351 usePardiso=1 352 mkl_blacs_64=[[]] 353 mkl_blacs_32=[[]] 354 if useCPardiso or usePardiso: 355 self.logPrintBox('BLASLAPACK: Looking for multi-threaded MKL for C/Pardiso') 356 for libdir in self.libDirs: 357 if not os.path.exists(os.path.join(dir,libdir)): 358 self.logPrint('MKL Path not found.. skipping: '+os.path.join(dir,libdir)) 359 else: 360 self.log.write('Files and directories in that directory:\n'+str(os.listdir(os.path.join(dir,libdir)))+'\n') 361 # iomp5 is provided by the Intel compilers on macOS. Run source /opt/intel/bin/compilervars.sh intel64 to have it added to LIBRARY_PATH 362 # then locate libimp5.dylib in the LIBRARY_PATH and copy it to os.path.join(dir,libdir) 363 for i in mkl_blacs_64: 364 yield ('User specified MKL-C/Pardiso Intel-Linux64', None, [os.path.join(dir,libdir,'libmkl_intel'+ILP64+'.a'),'mkl_core','mkl_intel_thread']+i+['iomp5','dl','pthread'],known,'yes') 365 yield ('User specified MKL-C/Pardiso GNU-Linux64', None, [os.path.join(dir,libdir,'libmkl_intel'+ILP64+'.a'),'mkl_core','mkl_gnu_thread']+i+['gomp','dl','pthread'],known,'yes') 366 yield ('User specified MKL-Pardiso Intel-Windows64', None, [os.path.join(dir,libdir,'mkl_core.lib'),'mkl_intel'+ILP64+'.lib','mkl_intel_thread.lib']+i+['libiomp5md.lib'],known,'yes') 367 for i in mkl_blacs_32: 368 yield ('User specified MKL-C/Pardiso Intel-Linux32', None, [os.path.join(dir,libdir,'libmkl_intel.a'),'mkl_core','mkl_intel_thread']+i+['iomp5','dl','pthread'],'32','yes') 369 yield ('User specified MKL-C/Pardiso GNU-Linux32', None, [os.path.join(dir,libdir,'libmkl_intel.a'),'mkl_core','mkl_gnu_thread']+i+['gomp','dl','pthread'],'32','yes') 370 yield ('User specified MKL-Pardiso Intel-Windows32', None, [os.path.join(dir,libdir,'mkl_core.lib'),'mkl_intel_c.lib','mkl_intel_thread.lib']+i+['libiomp5md.lib'],'32','yes') 371 return 372 373 self.log.write('Files and directories in that directory:\n'+str(os.listdir(dir))+'\n') 374 # Check MATLAB [ILP64] MKL 375 yield ('User specified MATLAB [ILP64] MKL Linux lib dir', None, [os.path.join(dir,'bin','glnxa64','mkl.so'), os.path.join(dir,'sys','os','glnxa64','libiomp5.so'), 'pthread'],'64','yes') 376 oldFlags = self.setCompilers.LDFLAGS 377 self.setCompilers.LDFLAGS += '-Wl,-rpath,'+os.path.join(dir,'bin','maci64') 378 yield ('User specified MATLAB [ILP64] MKL macOS lib dir', None, [os.path.join(dir,'bin','maci64','mkl.dylib'), os.path.join(dir,'sys','os','maci64','libiomp5.dylib'), 'pthread'],'64','yes') 379 self.setCompilers.LDFLAGS = oldFlags 380 for ITHREAD in ITHREADS: 381 yield ('User specified MKL11/12 and later', None, [os.path.join(dir,'libmkl_intel'+ILP64+'.a'),'mkl_core','mkl_'+ITHREAD,'pthread'],known,ompthread) 382 # Some new MKL 11/12 variations 383 for libdir in self.libDirs: 384 if not os.path.exists(os.path.join(dir,libdir)): 385 self.logPrint('MKL Path not found.. skipping: '+os.path.join(dir,libdir)) 386 else: 387 self.log.write('Files and directories in that directory:\n'+str(os.listdir(os.path.join(dir,libdir)))+'\n') 388 for ITHREAD in ITHREADS: 389 yield ('User specified MKL11/12 Linux32', None, [os.path.join(dir,libdir,'libmkl_intel'+ILP64+'.a'),'mkl_core','mkl_'+ITHREAD,'pthread'],known,ompthread) 390 yield ('User specified MKL11/12 Linux32 for static linking (Cray)', None, ['-Wl,--start-group',os.path.join(dir,libdir,'libmkl_intel'+ILP64+'.a'),'mkl_core','mkl_'+ITHREAD,'-Wl,--end-group','pthread'],known,ompthread) 391 for libdir in self.libDirs: 392 if not os.path.exists(os.path.join(dir,libdir)): 393 self.logPrint('MKL Path not found.. skipping: '+os.path.join(dir,libdir)) 394 else: 395 self.log.write('Files and directories in that directory:\n'+str(os.listdir(os.path.join(dir,libdir)))+'\n') 396 for ITHREAD in ITHREADS: 397 yield ('User specified MKL11+ Linux64', None, [os.path.join(dir,libdir,'libmkl_intel'+ILP64+'.a'),'mkl_core','mkl_'+ITHREAD,'mkl_def','pthread'],known,ompthread) 398 yield ('User specified MKL11+ Mac-64', None, [os.path.join(dir,libdir,'libmkl_intel'+ILP64+'.a'),'mkl_core','mkl_'+ITHREAD,'pthread'],known,ompthread) 399 # Older Linux MKL checks 400 yield ('User specified MKL Linux lib dir', None, [os.path.join(dir, 'libmkl_lapack.a'), 'mkl', 'guide', 'pthread'],'32','no') 401 for libdir in self.libDirs: 402 if not os.path.exists(os.path.join(dir,libdir)): 403 self.logPrint('MKL Path not found.. skipping: '+os.path.join(dir,libdir)) 404 else: 405 self.log.write('Files and directories in that directory:\n'+str(os.listdir(os.path.join(dir,libdir)))+'\n') 406 yield ('User specified MKL Linux installation root', None, [os.path.join(dir,'lib',libdir,'libmkl_lapack.a'),'mkl', 'guide', 'pthread'],'32','no') 407 yield ('User specified MKL Linux-x86 lib dir', None, [os.path.join(dir, 'libmkl_lapack.a'), 'libmkl_def.a', 'guide', 'pthread'],'32','no') 408 yield ('User specified MKL Linux-x86 lib dir', None, [os.path.join(dir, 'libmkl_lapack.a'), 'libmkl_def.a', 'guide', 'vml','pthread'],'32','no') 409 yield ('User specified MKL Linux-ia64 lib dir', None, [os.path.join(dir, 'libmkl_lapack.a'), 'libmkl_ipf.a', 'guide', 'pthread'],'32','no') 410 yield ('User specified MKL Linux-em64t lib dir', None, [os.path.join(dir, 'libmkl_lapack.a'), 'libmkl_em64t.a', 'guide', 'pthread'],'32','no') 411 yield ('User specified MKL Linux-x86 installation root', None, [os.path.join(dir,'lib','32','libmkl_lapack.a'),'libmkl_def.a', 'guide', 'pthread'],'32','no') 412 yield ('User specified MKL Linux-x86 installation root', None, [os.path.join(dir,'lib','32','libmkl_lapack.a'),'libmkl_def.a', 'guide', 'vml','pthread'],'32','no') 413 yield ('User specified MKL Linux-ia64 installation root', None, [os.path.join(dir,'lib','64','libmkl_lapack.a'),'libmkl_ipf.a', 'guide', 'pthread'],'32','no') 414 yield ('User specified MKL Linux-em64t installation root', None, [os.path.join(dir,'lib','em64t','libmkl_lapack.a'),'libmkl_em64t.a', 'guide', 'pthread'],'32','no') 415 # Mac MKL check 416 yield ('User specified MKL Mac-x86 lib dir', None, [os.path.join(dir, 'libmkl_lapack.a'), 'libmkl_ia32.a', 'guide'],'32','no') 417 yield ('User specified MKL Max-x86 installation root', None, [os.path.join(dir,'Libraries','32','libmkl_lapack.a'),'libmkl_ia32.a', 'guide'],'32','no') 418 yield ('User specified MKL Max-x86 installation root', None, [os.path.join(dir,'lib','32','libmkl_lapack.a'),'libmkl_ia32.a', 'guide'],'32','no') 419 yield ('User specified MKL Mac-em64t lib dir', None, [os.path.join(dir, 'libmkl_lapack.a'), 'libmkl_intel'+ILP64+'.a', 'guide'],known,'no') 420 yield ('User specified MKL Max-em64t installation root', None, [os.path.join(dir,'Libraries','32','libmkl_lapack.a'),'libmkl_intel'+ILP64+'.a', 'guide'],'32','no') 421 yield ('User specified MKL Max-em64t installation root', None, [os.path.join(dir,'lib','32','libmkl_lapack.a'),'libmkl_intel'+ILP64+'.a', 'guide'],'32','no') 422 # Check MKL on windows 423 yield ('User specified MKL Windows lib dir', None, [os.path.join(dir, 'mkl_c_dll.lib')],'32','no') 424 yield ('User specified stdcall MKL Windows lib dir', None, [os.path.join(dir, 'mkl_s_dll.lib')],'32','no') 425 yield ('User specified ia64/em64t MKL Windows lib dir', None, [os.path.join(dir, 'mkl_dll.lib')],'32','no') 426 for ITHREAD in ITHREADS: 427 yield ('User specified MKL10-32 Windows lib dir', None, [os.path.join(dir, 'mkl_intel_c_dll.lib'),'mkl_'+ITHREAD+'_dll.lib','mkl_core_dll.lib','libiomp5md.lib'],'32',ompthread) 428 yield ('User specified MKL10-32 Windows stdcall lib dir', None, [os.path.join(dir, 'mkl_intel_s_dll.lib'),'mkl_'+ITHREAD+'_dll.lib','mkl_core_dll.lib','libiomp5md.lib'],'32',ompthread) 429 yield ('User specified MKL10-64 Windows lib dir', None, [os.path.join(dir, 'mkl_intel'+ILP64+'_dll.lib'),'mkl_'+ITHREAD+'_dll.lib','mkl_core_dll.lib','libiomp5md.lib'],known,ompthread) 430 mkldir = os.path.join(dir, 'ia32', 'lib') 431 yield ('User specified MKL Windows installation root', None, [os.path.join(mkldir, 'mkl_c_dll.lib')],'32','no') 432 yield ('User specified stdcall MKL Windows installation root', None, [os.path.join(mkldir, 'mkl_s_dll.lib')],'32','no') 433 for ITHREAD in ITHREADS: 434 yield ('User specified MKL10-32 Windows installation root', None, [os.path.join(mkldir, 'mkl_intel_c_dll.lib'),'mkl_'+ITHREAD+'_dll.lib','mkl_core_dll.lib','libiomp5md.lib'],'32',ompthread) 435 yield ('User specified MKL10-32 Windows stdcall installation root', None, [os.path.join(mkldir, 'mkl_intel_s_dll.lib'),'mkl_'+ITHREAD+'_dll.lib','mkl_core_dll.lib','libiomp5md.lib'],'32',ompthread) 436 mkldir = os.path.join(dir, 'em64t', 'lib') 437 for ITHREAD in ITHREADS: 438 yield ('User specified MKL10-64 Windows installation root', None, [os.path.join(mkldir, 'mkl_intel'+ILP64+'_dll.lib'),'mkl_'+ITHREAD+'_dll.lib','mkl_core_dll.lib','libiomp5md.lib'],known,ompthread) 439 yield ('User specified em64t MKL Windows installation root', None, [os.path.join(mkldir, 'mkl_dll.lib')],'32','no') 440 mkldir = os.path.join(dir, 'ia64', 'lib') 441 yield ('User specified ia64 MKL Windows installation root', None, [os.path.join(mkldir, 'mkl_dll.lib')],'32','no') 442 for ITHREAD in ITHREADS: 443 yield ('User specified MKL10-64 Windows installation root', None, [os.path.join(mkldir, 'mkl_intel'+ILP64+'_dll.lib'),'mkl_'+ITHREAD+'_dll.lib','mkl_core_dll.lib','libiomp5md.lib'],known,ompthread) 444 # Check AMD ACML libraries 445 yield ('User specified AMD ACML lib dir', None, os.path.join(dir,'lib','libacml.a'),'32','unknown') 446 yield ('User specified AMD ACML lib dir', None, [os.path.join(dir,'lib','libacml.a'), os.path.join(dir,'lib','libacml_mv.a')],'32','unknown') 447 yield ('User specified AMD ACML lib dir', None, os.path.join(dir,'lib','libacml_mp.a'),'32','unknown') 448 yield ('User specified AMD ACML lib dir', None, [os.path.join(dir,'lib','libacml_mp.a'), os.path.join(dir,'lib','libacml_mv.a')],'32','unknown') 449 # Check BLIS/AMD-AOCL libraries 450 for lib in blislib: 451 for lapack in ['libflame.a','liblapack.a']: 452 for libdir in [dir,os.path.join(dir,'lib')]: 453 yield ('User specified installation root BLIS/AMD-AOCL', os.path.join(libdir,lib), os.path.join(libdir,lapack), 'unknown', 'unknown') 454 # NEC 455 yield ('User specified NEC lib dir', os.path.join(dir, 'lib', 'libblas_sequential.a'), [os.path.join(dir, 'lib', 'liblapack.a'), os.path.join(dir, 'lib', 'libasl_sequential.a')], 'unknown', 'unknown') 456 yield ('User specified NEC lib dir', os.path.join(dir, 'lib', 'libblas_sequential.a'), os.path.join(dir, 'lib', 'liblapack.a'), 'unknown', 'unknown') 457 # Search for FlexiBLAS 458 for libdir in ['lib64', 'lib', '']: 459 if os.path.exists(os.path.join(dir,libdir)): 460 yield ('User specified FlexiBLAS',None,os.path.join(dir,libdir,flexiblas),known,'unknown') 461 # Search for OpenBLAS 462 for libdir in ['lib','']: 463 if os.path.exists(os.path.join(dir,libdir)): 464 yield ('User specified OpenBLAS',None,os.path.join(dir,libdir,'libopenblas.a'),'unknown','unknown') 465 # Search for atlas 466 yield ('User specified ATLAS Linux installation root', [os.path.join(dir, 'libcblas.a'),os.path.join(dir, 'libf77blas.a'), os.path.join(dir, 'libatlas.a')], [os.path.join(dir, 'liblapack.a')],'32','no') 467 yield ('User specified ATLAS Linux installation root', [os.path.join(dir, 'libf77blas.a'), os.path.join(dir, 'libatlas.a')], [os.path.join(dir, 'liblapack.a')],'32','no') 468 469 yield ('User specified installation root (HPUX)', os.path.join(dir, 'libveclib.a'), os.path.join(dir, 'liblapack.a'),'32','unknown') 470 for libdir in ['lib64','lib','']: 471 if os.path.exists(os.path.join(dir,libdir)): 472 yield ('User specified installation root (F2CBLASLAPACK)', os.path.join(dir,libdir,'libf2cblas.a'), os.path.join(dir,libdir,'libf2clapack.a'),'32','no') 473 yield ('User specified installation root(NETLIB-LAPACK)', os.path.join(dir, 'libnblas.a'), os.path.join(dir, 'libnlapack.a'),'32','no') 474 yield ('User specified installation root(FBLASLAPACK)', os.path.join(dir, 'libfblas.a'), os.path.join(dir, 'libflapack.a'),'32','no') 475 for lib in ['','lib64']: 476 yield ('User specified installation root IBM ESSL', None, os.path.join(dir, lib, 'libessl.a'),'32','unknown') 477 # Search for liblapack.a and libblas.a after the implementations with more specific name to avoid 478 # finding these in /usr/lib despite using -L<blaslapack-dir> while attempting to get a different library. 479 for libdir in ['lib64','lib','']: 480 if os.path.exists(os.path.join(dir,libdir)): 481 yield ('User specified installation root BLAS/LAPACK',os.path.join(dir,libdir,'libblas.a'),os.path.join(dir,libdir,'liblapack.a'),'unknown','unknown') 482 if hasattr(self,'checkingMKROOTautomatically'): 483 raise RuntimeError('Unable to locate working BLAS/LAPACK libraries, even tried libraries in MKLROOT '+self.argDB['with-blaslapack-dir']+'\n') 484 else: 485 raise RuntimeError('You set a value for --with-blaslapack-dir=<dir>, but '+self.argDB['with-blaslapack-dir']+' cannot be used\n') 486 if self.defaultPrecision == '__float128': 487 raise RuntimeError('__float128 precision requires f2c libraries; suggest --download-f2cblaslapack\n') 488 489 # Try compiler defaults 490 yield ('Default compiler libraries', '', '','unknown','unknown') 491 yield ('Default NEC', 'libblas_sequential.a', ['liblapack.a','libasl_sequential.a'],'unknown','unknown') 492 yield ('Default NEC', 'libblas_sequential.a', 'liblapack.a','unknown','unknown') 493 yield ('Default FlexiBLAS', None, flexiblas, known, 'unknown') 494 for lib in blislib: 495 for lapack in ['libflame.a','liblapack.a']: 496 yield ('Default BLIS/AMD-AOCL', lib, lapack,'unknown','unknown') 497 yield ('Default compiler locations', 'libblas.a', 'liblapack.a','unknown','unknown') 498 yield ('Default compiler locations (all contained in libblas)', None, 'libblas.a','unknown','unknown') 499 yield ('Default NVHPC', None, ['liblapack.a','libblas.a','libnvf.a','librt.a'],'unknown','unknown') 500 yield ('Default OpenBLAS', None, 'libopenblas.a','unknown','unknown') 501 # Intel on Mac 502 for ITHREAD in ITHREADS: 503 yield ('User specified MKL Mac-64', None, [os.path.join('/opt','intel','mkl','lib','libmkl_intel'+ILP64+'.a'),'mkl_'+ITHREAD,'mkl_core','pthread'],known,ompthread) 504 # Try Microsoft Windows location 505 for MKL_Version in [os.path.join('MKL','9.0'),os.path.join('MKL','8.1.1'),os.path.join('MKL','8.1'),os.path.join('MKL','8.0.1'),os.path.join('MKL','8.0'),'MKL72','MKL70','MKL61','MKL']: 506 mklpath = os.path.join('/cygdrive', 'c', 'Program Files', 'Intel', MKL_Version) 507 if not os.path.exists(mklpath): 508 self.logPrint('MKL Path not found.. skipping: '+mklpath) 509 else: 510 mkldir = os.path.join(mklpath, 'ia32', 'lib') 511 yield ('Microsoft Windows, Intel MKL library', None, os.path.join(mkldir,'mkl_c_dll.lib'),'32','no') 512 yield ('Microsoft Windows, Intel MKL stdcall library', None, os.path.join(mkldir,'mkl_s_dll.lib'),'32','no') 513 mkldir = os.path.join(mklpath, 'em64t', 'lib') 514 yield ('Microsoft Windows, em64t Intel MKL library', None, os.path.join(mkldir,'mkl_dll.lib'),'32','no') 515 mkldir = os.path.join(mklpath, 'ia64', 'lib') 516 yield ('Microsoft Windows, ia64 Intel MKL library', None, os.path.join(mkldir,'mkl_dll.lib'),'32','no') 517 # IRIX locations 518 yield ('IRIX Mathematics library', None, 'libcomplib.sgimath.a','32','unknown') 519 yield ('Another IRIX Mathematics library', None, 'libscs.a','32','unknown') 520 yield ('Compaq/Alpha Mathematics library', None, 'libcxml.a','32','unknown') 521 # IBM ESSL locations 522 yield ('IBM ESSL Mathematics library', None, 'libessl.a','32','unknown') 523 yield ('IBM ESSL Mathematics library for Blue Gene', None, 'libesslbg.a','32','unknown') 524 yield ('HPUX', 'libveclib.a', 'liblapack.a','unknown','unknown') 525 # /usr/local/lib 526 dir = os.path.join('/usr','local','lib') 527 yield ('Default compiler locations /usr/local/lib', os.path.join(dir,'libblas.a'), os.path.join(dir,'liblapack.a'),'unknown','unknown') 528 yield ('Default compiler locations /usr/local/lib', None, os.path.join(dir,'libopenblas.a'),'unknown','unknown') 529 yield ('Default compiler locations with gfortran', None, ['liblapack.a', 'libblas.a','libgfortran.a'],'unknown','unknown') 530 yield ('Default Atlas location',['libcblas.a','libf77blas.a','libatlas.a'], ['liblapack.a'],'unknown','unknown') 531 yield ('Default Atlas location',['libf77blas.a','libatlas.a'], ['liblapack.a'],'unknown','unknown') 532 yield ('Default compiler locations with G77', None, ['liblapack.a', 'libblas.a','libg2c.a'],'unknown','unknown') 533 # Try macOS location 534 dir = os.path.join('/Library', 'Frameworks', 'Intel_MKL.framework','Libraries','32') 535 yield ('macOS with Intel MKL', None, [os.path.join(dir,'libmkl_lapack.a'),'libmkl_ia32.a','libguide.a'],'32','no') 536 yield ('macOS BLAS/LAPACK library', None, os.path.join('/System', 'Library', 'Frameworks', 'vecLib.framework', 'vecLib'),'32','unknown') 537 # Sun locations; this don't currently work 538 yield ('Sun sunperf BLAS/LAPACK library', None, ['libsunperf.a','libsunmath.a'],'32','no') 539 yield ('Sun sunperf BLAS/LAPACK library', None, ['libsunperf.a','libF77.a','libM77.a','libsunmath.a'],'32','no') 540 yield ('Sun sunperf BLAS/LAPACK library', None, ['libsunperf.a','libfui.a','libfsu.a','libsunmath.a'],'32','no') 541 # Try Microsoft Windows location 542 for MKL_Version in [os.path.join('MKL','9.0'),os.path.join('MKL','8.1.1'),os.path.join('MKL','8.1'),os.path.join('MKL','8.0.1'),os.path.join('MKL','8.0'),'MKL72','MKL70','MKL61','MKL']: 543 mklpath = os.path.join('/cygdrive', 'c', 'Program Files', 'Intel', MKL_Version) 544 if not os.path.exists(mklpath): 545 self.logPrint('MKL Path not found.. skipping: '+mklpath) 546 else: 547 mkldir = os.path.join(mklpath, 'ia32', 'lib') 548 if os.path.exists(mkldir): 549 self.log.write('Files and directories in that directory:\n'+str(os.listdir(mkldir))+'\n') 550 yield ('Microsoft Windows, Intel MKL library', None, os.path.join(mkldir,'mkl_c_dll.lib'),'32','no') 551 yield ('Microsoft Windows, Intel MKL stdcall library', None, os.path.join(mkldir,'mkl_s_dll.lib'),'32','no') 552 mkldir = os.path.join(mklpath, 'em64t', 'lib') 553 if os.path.exists(mkldir): 554 self.log.write('Files and directories in that directory:\n'+str(os.listdir(mkldir))+'\n') 555 yield ('Microsoft Windows, em64t Intel MKL library', None, os.path.join(mkldir,'mkl_dll.lib'),'32','no') 556 mkldir = os.path.join(mklpath, 'ia64', 'lib') 557 if os.path.exists(mkldir): 558 self.log.write('Files and directories in that directory:\n'+str(os.listdir(mkldir))+'\n') 559 yield ('Microsoft Windows, ia64 Intel MKL library', None, os.path.join(mkldir,'mkl_dll.lib'),'32','no') 560 return 561 562 def configureLibrary(self): 563 if hasattr(self.compilers, 'FC'): 564 self.alternativedownload = 'fblaslapack' 565 566 # find working BLAS/LAPACK 567 self.foundBlas = 0 568 self.foundLapack = 0 569 for (name, blasLibrary, lapackLibrary, known64, usesopenmp) in self.generateGuesses(): 570 self.log.write('================================================================================\n') 571 self.log.write('Checking for BLAS and LAPACK in '+name+'\n') 572 (foundBlas, foundLapack) = self.executeTest(self.checkLib, [lapackLibrary, blasLibrary]) 573 if foundBlas and foundLapack: 574 self.foundBlas = 1 575 self.foundLapack = 1 576 self.known64 = known64 577 self.usesopenmp = usesopenmp 578 if not isinstance(blasLibrary, list): 579 self.blasLibrary = [blasLibrary] 580 else: 581 self.blasLibrary = blasLibrary 582 if not isinstance(lapackLibrary, list): 583 self.lapackLibrary = [lapackLibrary] 584 else: 585 self.lapackLibrary = lapackLibrary 586 self.lib = [] 587 if self.lapackLibrary[0]: 588 self.lib.extend(self.lapackLibrary) 589 if self.blasLibrary[0]: 590 self.lib.extend(self.blasLibrary) 591 self.dlib = self.lib+self.dlib 592 self.framework.packages.append(self) 593 break 594 self.include = [] 595 596 # error if not found 597 if not self.foundBlas: 598 # check for split blas/blas-dev packages 599 import glob 600 blib = glob.glob('/usr/lib/libblas.*') 601 if blib != [] and not (os.path.isfile('/usr/lib/libblas.so') or os.path.isfile('/usr/lib/libblas.a')): 602 raise RuntimeError('Incomplete system BLAS install detected. Perhaps you need to install blas-dev or blas-devel package - that contains /usr/lib/libblas.so using apt or yum or equivalent package manager?') 603 if 'known-blaslapack-mangling' in self.argDB: 604 known_mangling = self.argDB['known-blaslapack-mangling'] 605 raise RuntimeError('Failed to automatically detect BLAS libraries matching the mangling set with --known-blaslapack-mangling='+known_mangling+', try removing this for automatically detected mangling.') 606 if hasattr(self.compilers, 'FC') and (self.defaultPrecision != '__float128') and (self.defaultPrecision != '__fp16'): 607 pkg = 'fblaslapack' 608 else: 609 pkg = 'f2cblaslapack' 610 raise RuntimeError('Could not find a functional BLAS. Run with --with-blas-lib=<lib> to indicate the library containing BLAS.\n Or --download-'+pkg+'=1 to have one automatically downloaded and installed\n') 611 if not self.foundLapack: 612 # check for split blas/blas-dev packages 613 import glob 614 llib = glob.glob('/usr/lib/liblapack.*') 615 if llib != [] and not (os.path.isfile('/usr/lib/liblapack.so') or os.path.isfile('/usr/lib/liblapack.a')): 616 raise RuntimeError('Incomplete system LAPACK install detected. Perhaps you need to install lapack-dev or lapack-devel package - that contains /usr/lib/liblapack.so using apt or yum or equivalent package manager?') 617 if 'known-blaslapack-mangling' in self.argDB: 618 known_mangling = self.argDB['known-blaslapack-mangling'] 619 raise RuntimeError('Failed to automatically detect LAPACK libraries matching the mangling set with --known-blaslapack-mangling='+known_mangling+', try removing this for automatically detected mangling.') 620 if hasattr(self.compilers, 'FC') and (self.defaultPrecision != '__float128') and (self.defaultPrecision != '__fp16'): 621 pkg = 'fblaslapack' 622 else: 623 pkg = 'f2cblaslapack' 624 raise RuntimeError('Could not find a functional LAPACK. Run with --with-lapack-lib=<lib> to indicate the library containing LAPACK.\n Or --download-'+pkg+'=1 to have one automatically downloaded and installed\n') 625 626 self.found = 1 627 628 if self.mangling == 'underscore': 629 self.addDefine('BLASLAPACK_UNDERSCORE', 1) 630 elif self.mangling == 'caps': 631 self.addDefine('BLASLAPACK_CAPS', 1) 632 633 if self.suffix != '': 634 self.addDefine('BLASLAPACK_SUFFIX', self.suffix) 635 636 if self.f2cblaslapack.found: 637 oldLibs = self.compilers.LIBS 638 routine___float128 = self.mangleBlasNoPrefix('qdot') 639 routine___fp16 = self.mangleBlasNoPrefix('hdot') 640 self.libraries.saveLog() 641 if self.defaultPrecision != '__float128': 642 found = self.libraries.check(self.blasLibrary, routine___float128, fortranMangle = 0) 643 if found: 644 self.addDefine('HAVE_F2CBLASLAPACK___FLOAT128_BINDINGS', 1) 645 if self.defaultPrecision != '__fp16': 646 found = self.libraries.check(self.blasLibrary, routine___fp16, fortranMangle = 0) 647 if found: 648 self.addDefine('HAVE_F2CBLASLAPACK___FP16_BINDINGS', 1) 649 self.logWrite(self.libraries.restoreLog()) 650 self.compilers.LIBS = oldLibs 651 652 if not self.f2cblaslapack.found and not self.netliblapack.found and not self.fblaslapack.found: 653 self.executeTest(self.checkMKL) 654 if not self.mkl: 655 self.executeTest(self.checkESSL) 656 self.executeTest(self.checkPESSL) 657 self.executeTest(self.checkMissing) 658 self.executeTest(self.checklsame) 659 660 # check for shared library support 661 if self.argDB['with-shared-libraries']: 662 symbol = self.mangleBlas('geev') 663 if not self.setCompilers.checkIntoShared(symbol,self.lapackLibrary+self.getOtherLibs()): 664 raise RuntimeError('The BLAS/LAPACK libraries '+self.libraries.toStringNoDupes(self.lapackLibrary+self.getOtherLibs())+'\ncannot be used with a shared library\nEither run ./configure with --with-shared-libraries=0 or use a different BLAS/LAPACK library'); 665 666 # set self.has64bitindices 667 self.executeTest(self.checkRuntimeIssues) 668 if self.mkl and self.has64bitindices: 669 self.addDefine('HAVE_MKL_INTEL_ILP64',1) 670 if self.argDB['with-64-bit-blas-indices'] and not self.has64bitindices: 671 raise RuntimeError('You requested 64-bit integer BLAS/LAPACK using --with-64-bit-blas-indices but they are not available given your other BLAS/LAPACK options') 672 if self.libraries.check(self.dlib, 'bli_thread_set_num_threads') and not self.libraries.check(self.dlib, 'flexiblas_avail'): 673 self.addDefine('HAVE_BLI_THREAD_SET_NUM_THREADS',1) 674 if self.libraries.check(self.dlib, 'openblas_set_num_threads') and not self.libraries.check(self.dlib, 'flexiblas_avail'): 675 self.addDefine('HAVE_OPENBLAS_SET_NUM_THREADS',1) 676 if self.libraries.check(self.dlib, 'APL_dgemm') and not self.libraries.check(self.dlib, 'flexiblas_avail'): 677 self.addDefine('HAVE_APPLE_ACCELERATE',1) 678 679 def checkMKL(self): 680 '''Check for Intel MKL library''' 681 self.libraries.saveLog() 682 self.include = [] 683 self.defaultincludepath = False 684 if self.libraries.check(self.dlib, 'mkl_set_num_threads') and not self.libraries.check(self.dlib, 'flexiblas_avail'): 685 self.mkl = 1 686 self.addDefine('HAVE_MKL_LIBS',1) 687 '''Set include directory for mkl.h and friends''' 688 '''(the include directory is in CPATH if mklvars.sh has been sourced.''' 689 ''' if the script hasn't been sourced, we still try to pick up the include dir)''' 690 if 'with-blaslapack-include' in self.argDB: 691 incl = self.argDB['with-blaslapack-include'] 692 if not isinstance(incl, list): incl = [incl] 693 self.include = incl 694 if self.checkCompile('#include "mkl_spblas.h"',''): 695 self.mkl_spblas_h = 1 696 self.logPrint('MKL mkl_spblas.h found in default include path.') 697 self.defaultincludepath = True 698 else: 699 self.logPrint('MKL include path not automatically picked up by compiler. Trying to find mkl_spblas.h...') 700 if 'with-blaslapack-dir' in self.argDB: 701 pathlist = [os.path.join(self.argDB['with-blaslapack-dir'],'include'), 702 os.path.join(self.argDB['with-blaslapack-dir'],'..','include'), 703 os.path.join(self.argDB['with-blaslapack-dir'],'..','..','include')] 704 elif 'with-blaslapack-include' in self.argDB: 705 pathlist = self.include 706 else: 707 pathlist = [] 708 for path in pathlist: 709 if os.path.isdir(path) and self.checkInclude([path], ['mkl_spblas.h']): 710 self.include = [path] 711 self.mkl_spblas_h = 1 712 self.logPrint('MKL mkl_spblas.h found at:'+path) 713 break 714 715 if not self.mkl_spblas_h: 716 self.include = [] 717 self.logPrint('Unable to find MKL include directory!') 718 else: 719 self.logPrint('MKL include path set to ' + str(self.include)) 720 self.versionname = 'INTEL_MKL_VERSION' 721 self.versioninclude = 'mkl_version.h' 722 self.versiontitle = 'Intel MKL Version' 723 if hasattr(self,'dinclude'): 724 [self.dinclude.append(inc) for inc in self.include if inc not in self.dinclude] 725 else: 726 self.dinclude = self.include 727 self.checkVersion() 728 if self.include or self.defaultincludepath: 729 self.addDefine('HAVE_MKL_INCLUDES',1) 730 self.addDefine('HAVE_MKL_SET_NUM_THREADS',1) 731 self.logWrite(self.libraries.restoreLog()) 732 return 733 734 def checkESSL(self): 735 '''Check for the IBM ESSL library''' 736 self.libraries.saveLog() 737 if self.libraries.check(self.dlib, 'iessl'): 738 self.essl = 1 739 self.addDefine('HAVE_ESSL',1) 740 741 if 'with-blaslapack-include' in self.argDB: 742 incl = self.argDB['with-blaslapack-include'] 743 if not isinstance(incl, list): incl = [incl] 744 elif 'with-blaslapack-dir' in self.argDB: 745 incl = [os.path.join(self.argDB['with-blaslapack-dir'],'include')] 746 else: 747 return 748 linc = self.include + incl 749 if self.checkInclude(linc, ['essl.h']): 750 self.include = linc 751 self.logWrite(self.libraries.restoreLog()) 752 return 753 754 def checkPESSL(self): 755 '''Check for the IBM PESSL library - and error out - if used instead of ESSL''' 756 self.libraries.saveLog() 757 if self.libraries.check(self.dlib, 'ipessl'): 758 self.logWrite(self.libraries.restoreLog()) 759 raise RuntimeError('Cannot use PESSL instead of ESSL!') 760 self.logWrite(self.libraries.restoreLog()) 761 return 762 763 def mangleBlas(self, baseName, mangling = None): 764 prefix = self.getPrefix() 765 return self.mangleBlasNoPrefix(prefix+baseName, mangling) 766 767 def mangleBlasNoPrefix(self, baseName, mangling = None): 768 if mangling is None: 769 mangling = getattr(self, 'mangling', 'unknown') 770 771 if mangling == 'underscore': 772 if not self.f2c: 773 if getattr(self.compilers, 'fortranManglingDoubleUnderscore', False) and baseName.find('_') >= 0: 774 return baseName.lower()+self.suffix+'__' 775 return baseName.lower()+self.suffix+'_' 776 elif mangling == 'unchanged': 777 return baseName.lower()+self.suffix 778 elif mangling == 'caps': 779 return baseName.upper()+self.suffix 780 else: 781 return baseName+self.suffix 782 783 def checkMissing(self): 784 '''Check for missing LAPACK routines''' 785 if self.foundLapack and hasattr(self.compilers, 'FC') and not self.f2c and self.mangling == 'unknown': 786 mangling = self.compilers.fortranMangling 787 else: 788 mangling = self.mangling 789 routines = ['gelss','gerfs','gges','hgeqz','hseqr','orgqr','ormqr','stebz', 790 'stegr','stein','steqr','stev','sytri','tgsen','trsen','trtrs','geqp3'] 791 _, missing = self.checkLapack(self.lapackLibrary, self.getOtherLibs(), mangling, routines) 792 for baseName in routines: 793 if self.mangleBlas(baseName) in missing: 794 self.missingRoutines.append(baseName) 795 self.addDefine('MISSING_LAPACK_'+baseName.upper(), 1) 796 797 def checklsame(self): 798 ''' Do the BLAS/LAPACK libraries have a valid lsame() function with correct binding.''' 799 routine = 'lsame'; 800 found = self.checkForRoutine(routine) 801 if not found: 802 self.addDefine('MISSING_LAPACK_'+self.mangleBlasNoPrefix(routine), 1) 803 804 def checkForRoutine(self,routine): 805 ''' used by other packages to see if a BLAS routine is available 806 This is not really correct because other packages do not (usually) know about f2cblasLapack''' 807 self.libraries.saveLog() 808 mangled_name = self.mangleBlasNoPrefix(routine) 809 ret = self.libraries.check(self.dlib,mangled_name,fortranMangle = 0) 810 self.logWrite(self.libraries.restoreLog()) 811 return ret 812 813 def runTimeTest(self,name,includes,body,lib = None,nobatch=0): 814 '''Either runs a test or adds it to the batch of runtime tests''' 815 if name in self.framework.clArgDB: return self.argDB[name] 816 if self.argDB['with-batch']: 817 if nobatch: 818 raise RuntimeError('In batch mode you must provide the value for --'+name) 819 else: 820 self.framework.addBatchInclude(includes) 821 self.framework.addBatchBody(body) 822 if lib: self.framework.addBatchLib(lib) 823 if self.include: self.framework.batchIncludeDirs.extend([self.headers.getIncludeArgument(inc) for inc in self.include]) 824 return None 825 else: 826 result = None 827 self.pushLanguage('C') 828 filename = 'runtimetestoutput' 829 body = '''FILE *output = fopen("'''+filename+'''","w");\n'''+body 830 if lib: 831 if not isinstance(lib, list): lib = [lib] 832 oldLibs = self.compilers.LIBS 833 self.compilers.LIBS = self.libraries.toString(lib)+' '+self.compilers.LIBS 834 if self.checkRun(includes, body) and os.path.exists(filename): 835 f = open(filename) 836 out = f.read() 837 f.close() 838 os.remove(filename) 839 result = out.split("=")[1].split("'")[0] 840 self.popLanguage() 841 if lib: 842 self.compilers.LIBS = oldLibs 843 return result 844 845 def checkRuntimeIssues(self): 846 '''Determines if BLAS/LAPACK routines use 32 or 64-bit integers''' 847 if self.known64 == '64': 848 self.addDefine('HAVE_64BIT_BLAS_INDICES', 1) 849 self.has64bitindices = 1 850 self.log.write('64-bit BLAS indices based on the BLAS/LAPACK library being used\n') 851 elif self.known64 == '32': 852 self.log.write('32-bit BLAS indices based on the BLAS/LAPACK library being used\n') 853 elif 'known-64-bit-blas-indices' in self.argDB: 854 if self.argDB['known-64-bit-blas-indices']: 855 self.addDefine('HAVE_64BIT_BLAS_INDICES', 1) 856 self.has64bitindices = 1 857 else: 858 self.has64bitindices = 0 859 elif self.argDB['with-batch']: 860 self.logPrintWarning('Cannot determine if BLAS/LAPACK uses 32 or 64-bit integers \ 861in batch-mode! Assuming 32-bit integers. Run with --known-64-bit-blas-indices \ 862if you know they are 64-bit. Run with --known-64-bit-blas-indices=0 to remove \ 863this warning message') 864 self.has64bitindices = 0 865 self.log.write('In batch mode with unknown size of BLAS/LAPACK defaulting to 32-bit\n') 866 else: 867 includes = '''#include <sys/types.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <stddef.h>\n\n''' 868 t = self.getType() 869 body = '''extern '''+t+''' '''+self.mangleBlas('dot')+'''(const int*,const '''+t+'''*,const int *,const '''+t+'''*,const int*); 870 '''+t+''' x1mkl[4] = {3.0,5.0,7.0,9.0}; 871 int one1mkl = 1,nmkl = 2; 872 '''+t+''' dotresultmkl = 0; 873 dotresultmkl = '''+self.mangleBlas('dot')+'''(&nmkl,x1mkl,&one1mkl,x1mkl,&one1mkl); 874 fprintf(output, "-known-64-bit-blas-indices=%d",dotresultmkl != 34);''' 875 result = self.runTimeTest('known-64-bit-blas-indices',includes,body,self.dlib,nobatch=1) 876 if result is not None: 877 self.log.write('Checking for 64-bit BLAS/LAPACK indices: result ' +str(result)+'\n') 878 result = int(result) 879 if result: 880 if self.defaultPrecision == 'single': 881 self.log.write('Checking for 64-bit BLAS/LAPACK indices: special check for Apple single precision\n') 882 # On Apple single precision sdot() returns a double so we need to test that case 883 body = '''extern double '''+self.mangleBlas('dot')+'''(const int*,const '''+t+'''*,const int *,const '''+t+'''*,const int*); 884 '''+t+''' x1mkl[4] = {3.0,5.0,7.0,9.0}; 885 int one1mkl = 1,nmkl = 2; 886 double dotresultmkl = 0; 887 dotresultmkl = '''+self.mangleBlas('dot')+'''(&nmkl,x1mkl,&one1mkl,x1mkl,&one1mkl); 888 fprintf(output, "--known-64-bit-blas-indices=%d",dotresultmkl != 34);''' 889 result = self.runTimeTest('known-64-bit-blas-indices',includes,body,self.dlib,nobatch=1) 890 result = int(result) 891 if result: 892 self.addDefine('HAVE_64BIT_BLAS_INDICES', 1) 893 self.has64bitindices = 1 894 self.log.write('Checking for 64-bit BLAS/LAPACK indices: result not equal to 1 so assuming 64-bit BLAS/LAPACK indices\n') 895 else: 896 self.addDefine('HAVE_64BIT_BLAS_INDICES', 1) 897 self.has64bitindices = 1 898 self.log.write('Checking for 64-bit BLAS/LAPACK indices: program did not return therefore assuming 64-bit BLAS/LAPACK indices\n') 899 self.log.write('Checking if sdot() returns a float or a double\n') 900 if 'known-sdot-returns-double' in self.argDB: 901 if self.argDB['known-sdot-returns-double']: 902 self.addDefine('BLASLAPACK_SDOT_RETURNS_DOUBLE', 1) 903 elif self.argDB['with-batch']: 904 self.logPrintWarning('Cannot determine if BLAS sdot() returns a float or a double \ 905in batch-mode! Assuming float. Run with --known-sdot-returns-double=1 \ 906if you know it returns a double (very unlikely). Run with \ 907--known-sdot-returns-double=0 to remove this warning message') 908 else: 909 includes = '''#include <sys/types.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <stddef.h>\n''' 910 body = '''extern float '''+self.mangleBlasNoPrefix('sdot')+'''(const int*,const float*,const int *,const float*,const int*); 911 float x1[1] = {3.0}; 912 int one1 = 1; 913 long long int ione1 = 1; 914 float sdotresult = 0; 915 int blasint64 = '''+str(self.has64bitindices)+''';\n 916 if (!blasint64) { 917 sdotresult = '''+self.mangleBlasNoPrefix('sdot')+'''(&one1,x1,&one1,x1,&one1); 918 } else { 919 sdotresult = '''+self.mangleBlasNoPrefix('sdot')+'''((const int*)&ione1,x1,(const int*)&ione1,x1,(const int*)&ione1); 920 } 921 fprintf(output, "--known-sdot-returns-double=%d",sdotresult != 9);\n''' 922 result = self.runTimeTest('known-sdot-returns-double',includes,body,self.dlib,nobatch=1) 923 if result: 924 self.log.write('Checking for sdot() return double: result ' +str(result)+'\n') 925 result = int(result) 926 if result: 927 self.addDefine('BLASLAPACK_SDOT_RETURNS_DOUBLE', 1) 928 self.log.write('Checking sdot(): Program did return with not 1 for output so assume returns double\n') 929 else: 930 self.log.write('Checking sdot(): Program did not return with output so assume returns single\n') 931 self.log.write('Checking if snrm() returns a float or a double\n') 932 if 'known-snrm2-returns-double' in self.argDB: 933 if self.argDB['known-snrm2-returns-double']: 934 self.addDefine('BLASLAPACK_SNRM2_RETURNS_DOUBLE', 1) 935 elif self.argDB['with-batch']: 936 self.logPrintWarning('Cannot determine if BLAS snrm2() returns a float or a double \ 937in batch-mode! Assuming float. Run with --known-snrm2-returns-double=1 \ 938if you know it returns a double (very unlikely). Run with \ 939--known-snrm2-returns-double=0 to remove this warning message') 940 else: 941 includes = '''#include <sys/types.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <stddef.h>\n''' 942 body = '''extern float '''+self.mangleBlasNoPrefix('snrm2')+'''(const int*,const float*,const int*); 943 float x2[1] = {3.0}; 944 int one2 = 1; 945 long long int ione2 = 1; 946 float normresult = 0; 947 int blasint64 = '''+str(self.has64bitindices)+''';\n 948 if (!blasint64) { 949 normresult = '''+self.mangleBlasNoPrefix('snrm2')+'''(&one2,x2,&one2); 950 } else { 951 normresult = '''+self.mangleBlasNoPrefix('snrm2')+'''((const int*)&ione2,x2,(const int*)&ione2); 952 } 953 fprintf(output, "--known-snrm2-returns-double=%d",normresult != 3);\n''' 954 result = self.runTimeTest('known-snrm2-returns-double',includes,body,self.dlib,nobatch=1) 955 if result: 956 self.log.write('Checking for snrm2() return double: result ' +str(result)+'\n') 957 result = int(result) 958 if result: 959 self.log.write('Checking snrm2(): Program did return with 1 for output so assume returns double\n') 960 self.addDefine('BLASLAPACK_SNRM2_RETURNS_DOUBLE', 1) 961 else: 962 self.log.write('Checking snrm2(): Program did not return with output so assume returns single\n') 963