Chris@87: #!/bin/env python Chris@87: """ Chris@87: This file defines a set of system_info classes for getting Chris@87: information about various resources (libraries, library directories, Chris@87: include directories, etc.) in the system. Currently, the following Chris@87: classes are available: Chris@87: Chris@87: atlas_info Chris@87: atlas_threads_info Chris@87: atlas_blas_info Chris@87: atlas_blas_threads_info Chris@87: lapack_atlas_info Chris@87: blas_info Chris@87: lapack_info Chris@87: openblas_info Chris@87: blas_opt_info # usage recommended Chris@87: lapack_opt_info # usage recommended Chris@87: fftw_info,dfftw_info,sfftw_info Chris@87: fftw_threads_info,dfftw_threads_info,sfftw_threads_info Chris@87: djbfft_info Chris@87: x11_info Chris@87: lapack_src_info Chris@87: blas_src_info Chris@87: numpy_info Chris@87: numarray_info Chris@87: numpy_info Chris@87: boost_python_info Chris@87: agg2_info Chris@87: wx_info Chris@87: gdk_pixbuf_xlib_2_info Chris@87: gdk_pixbuf_2_info Chris@87: gdk_x11_2_info Chris@87: gtkp_x11_2_info Chris@87: gtkp_2_info Chris@87: xft_info Chris@87: freetype2_info Chris@87: umfpack_info Chris@87: Chris@87: Usage: Chris@87: info_dict = get_info() Chris@87: where is a string 'atlas','x11','fftw','lapack','blas', Chris@87: 'lapack_src', 'blas_src', etc. For a complete list of allowed names, Chris@87: see the definition of get_info() function below. Chris@87: Chris@87: Returned info_dict is a dictionary which is compatible with Chris@87: distutils.setup keyword arguments. If info_dict == {}, then the Chris@87: asked resource is not available (system_info could not find it). Chris@87: Chris@87: Several *_info classes specify an environment variable to specify Chris@87: the locations of software. When setting the corresponding environment Chris@87: variable to 'None' then the software will be ignored, even when it Chris@87: is available in system. Chris@87: Chris@87: Global parameters: Chris@87: system_info.search_static_first - search static libraries (.a) Chris@87: in precedence to shared ones (.so, .sl) if enabled. Chris@87: system_info.verbosity - output the results to stdout if enabled. Chris@87: Chris@87: The file 'site.cfg' is looked for in Chris@87: Chris@87: 1) Directory of main setup.py file being run. Chris@87: 2) Home directory of user running the setup.py file as ~/.numpy-site.cfg Chris@87: 3) System wide directory (location of this file...) Chris@87: Chris@87: The first one found is used to get system configuration options The Chris@87: format is that used by ConfigParser (i.e., Windows .INI style). The Chris@87: section ALL has options that are the default for each section. The Chris@87: available sections are fftw, atlas, and x11. Appropiate defaults are Chris@87: used if nothing is specified. Chris@87: Chris@87: The order of finding the locations of resources is the following: Chris@87: 1. environment variable Chris@87: 2. section in site.cfg Chris@87: 3. ALL section in site.cfg Chris@87: Only the first complete match is returned. Chris@87: Chris@87: Example: Chris@87: ---------- Chris@87: [ALL] Chris@87: library_dirs = /usr/lib:/usr/local/lib:/opt/lib Chris@87: include_dirs = /usr/include:/usr/local/include:/opt/include Chris@87: src_dirs = /usr/local/src:/opt/src Chris@87: # search static libraries (.a) in preference to shared ones (.so) Chris@87: search_static_first = 0 Chris@87: Chris@87: [fftw] Chris@87: fftw_libs = rfftw, fftw Chris@87: fftw_opt_libs = rfftw_threaded, fftw_threaded Chris@87: # if the above aren't found, look for {s,d}fftw_libs and {s,d}fftw_opt_libs Chris@87: Chris@87: [atlas] Chris@87: library_dirs = /usr/lib/3dnow:/usr/lib/3dnow/atlas Chris@87: # for overriding the names of the atlas libraries Chris@87: atlas_libs = lapack, f77blas, cblas, atlas Chris@87: Chris@87: [x11] Chris@87: library_dirs = /usr/X11R6/lib Chris@87: include_dirs = /usr/X11R6/include Chris@87: ---------- Chris@87: Chris@87: Authors: Chris@87: Pearu Peterson , February 2002 Chris@87: David M. Cooke , April 2002 Chris@87: Chris@87: Copyright 2002 Pearu Peterson all rights reserved, Chris@87: Pearu Peterson Chris@87: Permission to use, modify, and distribute this software is given under the Chris@87: terms of the NumPy (BSD style) license. See LICENSE.txt that came with Chris@87: this distribution for specifics. Chris@87: Chris@87: NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. Chris@87: Chris@87: """ Chris@87: from __future__ import division, absolute_import, print_function Chris@87: Chris@87: import sys Chris@87: import os Chris@87: import re Chris@87: import copy Chris@87: import warnings Chris@87: from glob import glob Chris@87: from functools import reduce Chris@87: if sys.version_info[0] < 3: Chris@87: from ConfigParser import NoOptionError, ConfigParser Chris@87: else: Chris@87: from configparser import NoOptionError, ConfigParser Chris@87: Chris@87: from distutils.errors import DistutilsError Chris@87: from distutils.dist import Distribution Chris@87: import distutils.sysconfig Chris@87: from distutils import log Chris@87: from distutils.util import get_platform Chris@87: Chris@87: from numpy.distutils.exec_command import \ Chris@87: find_executable, exec_command, get_pythonexe Chris@87: from numpy.distutils.misc_util import is_sequence, is_string, \ Chris@87: get_shared_lib_extension Chris@87: from numpy.distutils.command.config import config as cmd_config Chris@87: from numpy.distutils.compat import get_exception Chris@87: import distutils.ccompiler Chris@87: import tempfile Chris@87: import shutil Chris@87: Chris@87: Chris@87: # Determine number of bits Chris@87: import platform Chris@87: _bits = {'32bit': 32, '64bit': 64} Chris@87: platform_bits = _bits[platform.architecture()[0]] Chris@87: Chris@87: Chris@87: def libpaths(paths, bits): Chris@87: """Return a list of library paths valid on 32 or 64 bit systems. Chris@87: Chris@87: Inputs: Chris@87: paths : sequence Chris@87: A sequence of strings (typically paths) Chris@87: bits : int Chris@87: An integer, the only valid values are 32 or 64. A ValueError exception Chris@87: is raised otherwise. Chris@87: Chris@87: Examples: Chris@87: Chris@87: Consider a list of directories Chris@87: >>> paths = ['/usr/X11R6/lib','/usr/X11/lib','/usr/lib'] Chris@87: Chris@87: For a 32-bit platform, this is already valid: Chris@87: >>> np.distutils.system_info.libpaths(paths,32) Chris@87: ['/usr/X11R6/lib', '/usr/X11/lib', '/usr/lib'] Chris@87: Chris@87: On 64 bits, we prepend the '64' postfix Chris@87: >>> np.distutils.system_info.libpaths(paths,64) Chris@87: ['/usr/X11R6/lib64', '/usr/X11R6/lib', '/usr/X11/lib64', '/usr/X11/lib', Chris@87: '/usr/lib64', '/usr/lib'] Chris@87: """ Chris@87: if bits not in (32, 64): Chris@87: raise ValueError("Invalid bit size in libpaths: 32 or 64 only") Chris@87: Chris@87: # Handle 32bit case Chris@87: if bits == 32: Chris@87: return paths Chris@87: Chris@87: # Handle 64bit case Chris@87: out = [] Chris@87: for p in paths: Chris@87: out.extend([p + '64', p]) Chris@87: Chris@87: return out Chris@87: Chris@87: Chris@87: if sys.platform == 'win32': Chris@87: default_lib_dirs = ['C:\\', Chris@87: os.path.join(distutils.sysconfig.EXEC_PREFIX, Chris@87: 'libs')] Chris@87: default_include_dirs = [] Chris@87: default_src_dirs = ['.'] Chris@87: default_x11_lib_dirs = [] Chris@87: default_x11_include_dirs = [] Chris@87: else: Chris@87: default_lib_dirs = libpaths(['/usr/local/lib', '/opt/lib', '/usr/lib', Chris@87: '/opt/local/lib', '/sw/lib'], platform_bits) Chris@87: default_include_dirs = ['/usr/local/include', Chris@87: '/opt/include', '/usr/include', Chris@87: # path of umfpack under macports Chris@87: '/opt/local/include/ufsparse', Chris@87: '/opt/local/include', '/sw/include', Chris@87: '/usr/include/suitesparse'] Chris@87: default_src_dirs = ['.', '/usr/local/src', '/opt/src', '/sw/src'] Chris@87: Chris@87: default_x11_lib_dirs = libpaths(['/usr/X11R6/lib', '/usr/X11/lib', Chris@87: '/usr/lib'], platform_bits) Chris@87: default_x11_include_dirs = ['/usr/X11R6/include', '/usr/X11/include', Chris@87: '/usr/include'] Chris@87: Chris@87: if os.path.exists('/usr/lib/X11'): Chris@87: globbed_x11_dir = glob('/usr/lib/*/libX11.so') Chris@87: if globbed_x11_dir: Chris@87: x11_so_dir = os.path.split(globbed_x11_dir[0])[0] Chris@87: default_x11_lib_dirs.extend([x11_so_dir, '/usr/lib/X11']) Chris@87: default_x11_include_dirs.extend(['/usr/lib/X11/include', Chris@87: '/usr/include/X11']) Chris@87: Chris@87: import subprocess as sp Chris@87: tmp = None Chris@87: try: Chris@87: # Explicitly open/close file to avoid ResourceWarning when Chris@87: # tests are run in debug mode Python 3. Chris@87: tmp = open(os.devnull, 'w') Chris@87: p = sp.Popen(["gcc", "-print-multiarch"], stdout=sp.PIPE, Chris@87: stderr=tmp) Chris@87: except (OSError, DistutilsError): Chris@87: # OSError if gcc is not installed, or SandboxViolation (DistutilsError Chris@87: # subclass) if an old setuptools bug is triggered (see gh-3160). Chris@87: pass Chris@87: else: Chris@87: triplet = str(p.communicate()[0].decode().strip()) Chris@87: if p.returncode == 0: Chris@87: # gcc supports the "-print-multiarch" option Chris@87: default_x11_lib_dirs += [os.path.join("/usr/lib/", triplet)] Chris@87: default_lib_dirs += [os.path.join("/usr/lib/", triplet)] Chris@87: finally: Chris@87: if tmp is not None: Chris@87: tmp.close() Chris@87: Chris@87: if os.path.join(sys.prefix, 'lib') not in default_lib_dirs: Chris@87: default_lib_dirs.insert(0, os.path.join(sys.prefix, 'lib')) Chris@87: default_include_dirs.append(os.path.join(sys.prefix, 'include')) Chris@87: default_src_dirs.append(os.path.join(sys.prefix, 'src')) Chris@87: Chris@87: default_lib_dirs = [_m for _m in default_lib_dirs if os.path.isdir(_m)] Chris@87: default_include_dirs = [_m for _m in default_include_dirs if os.path.isdir(_m)] Chris@87: default_src_dirs = [_m for _m in default_src_dirs if os.path.isdir(_m)] Chris@87: Chris@87: so_ext = get_shared_lib_extension() Chris@87: Chris@87: Chris@87: def get_standard_file(fname): Chris@87: """Returns a list of files named 'fname' from Chris@87: 1) System-wide directory (directory-location of this module) Chris@87: 2) Users HOME directory (os.environ['HOME']) Chris@87: 3) Local directory Chris@87: """ Chris@87: # System-wide file Chris@87: filenames = [] Chris@87: try: Chris@87: f = __file__ Chris@87: except NameError: Chris@87: f = sys.argv[0] Chris@87: else: Chris@87: sysfile = os.path.join(os.path.split(os.path.abspath(f))[0], Chris@87: fname) Chris@87: if os.path.isfile(sysfile): Chris@87: filenames.append(sysfile) Chris@87: Chris@87: # Home directory Chris@87: # And look for the user config file Chris@87: try: Chris@87: f = os.path.expanduser('~') Chris@87: except KeyError: Chris@87: pass Chris@87: else: Chris@87: user_file = os.path.join(f, fname) Chris@87: if os.path.isfile(user_file): Chris@87: filenames.append(user_file) Chris@87: Chris@87: # Local file Chris@87: if os.path.isfile(fname): Chris@87: filenames.append(os.path.abspath(fname)) Chris@87: Chris@87: return filenames Chris@87: Chris@87: Chris@87: def get_info(name, notfound_action=0): Chris@87: """ Chris@87: notfound_action: Chris@87: 0 - do nothing Chris@87: 1 - display warning message Chris@87: 2 - raise error Chris@87: """ Chris@87: cl = {'atlas': atlas_info, # use lapack_opt or blas_opt instead Chris@87: 'atlas_threads': atlas_threads_info, # ditto Chris@87: 'atlas_blas': atlas_blas_info, Chris@87: 'atlas_blas_threads': atlas_blas_threads_info, Chris@87: 'lapack_atlas': lapack_atlas_info, # use lapack_opt instead Chris@87: 'lapack_atlas_threads': lapack_atlas_threads_info, # ditto Chris@87: 'mkl': mkl_info, Chris@87: # openblas which may or may not have embedded lapack Chris@87: 'openblas': openblas_info, # use blas_opt instead Chris@87: # openblas with embedded lapack Chris@87: 'openblas_lapack': openblas_lapack_info, # use blas_opt instead Chris@87: 'lapack_mkl': lapack_mkl_info, # use lapack_opt instead Chris@87: 'blas_mkl': blas_mkl_info, # use blas_opt instead Chris@87: 'x11': x11_info, Chris@87: 'fft_opt': fft_opt_info, Chris@87: 'fftw': fftw_info, Chris@87: 'fftw2': fftw2_info, Chris@87: 'fftw3': fftw3_info, Chris@87: 'dfftw': dfftw_info, Chris@87: 'sfftw': sfftw_info, Chris@87: 'fftw_threads': fftw_threads_info, Chris@87: 'dfftw_threads': dfftw_threads_info, Chris@87: 'sfftw_threads': sfftw_threads_info, Chris@87: 'djbfft': djbfft_info, Chris@87: 'blas': blas_info, # use blas_opt instead Chris@87: 'lapack': lapack_info, # use lapack_opt instead Chris@87: 'lapack_src': lapack_src_info, Chris@87: 'blas_src': blas_src_info, Chris@87: 'numpy': numpy_info, Chris@87: 'f2py': f2py_info, Chris@87: 'Numeric': Numeric_info, Chris@87: 'numeric': Numeric_info, Chris@87: 'numarray': numarray_info, Chris@87: 'numerix': numerix_info, Chris@87: 'lapack_opt': lapack_opt_info, Chris@87: 'blas_opt': blas_opt_info, Chris@87: 'boost_python': boost_python_info, Chris@87: 'agg2': agg2_info, Chris@87: 'wx': wx_info, Chris@87: 'gdk_pixbuf_xlib_2': gdk_pixbuf_xlib_2_info, Chris@87: 'gdk-pixbuf-xlib-2.0': gdk_pixbuf_xlib_2_info, Chris@87: 'gdk_pixbuf_2': gdk_pixbuf_2_info, Chris@87: 'gdk-pixbuf-2.0': gdk_pixbuf_2_info, Chris@87: 'gdk': gdk_info, Chris@87: 'gdk_2': gdk_2_info, Chris@87: 'gdk-2.0': gdk_2_info, Chris@87: 'gdk_x11_2': gdk_x11_2_info, Chris@87: 'gdk-x11-2.0': gdk_x11_2_info, Chris@87: 'gtkp_x11_2': gtkp_x11_2_info, Chris@87: 'gtk+-x11-2.0': gtkp_x11_2_info, Chris@87: 'gtkp_2': gtkp_2_info, Chris@87: 'gtk+-2.0': gtkp_2_info, Chris@87: 'xft': xft_info, Chris@87: 'freetype2': freetype2_info, Chris@87: 'umfpack': umfpack_info, Chris@87: 'amd': amd_info, Chris@87: }.get(name.lower(), system_info) Chris@87: return cl().get_info(notfound_action) Chris@87: Chris@87: Chris@87: class NotFoundError(DistutilsError): Chris@87: """Some third-party program or library is not found.""" Chris@87: Chris@87: Chris@87: class AtlasNotFoundError(NotFoundError): Chris@87: """ Chris@87: Atlas (http://math-atlas.sourceforge.net/) libraries not found. Chris@87: Directories to search for the libraries can be specified in the Chris@87: numpy/distutils/site.cfg file (section [atlas]) or by setting Chris@87: the ATLAS environment variable.""" Chris@87: Chris@87: Chris@87: class LapackNotFoundError(NotFoundError): Chris@87: """ Chris@87: Lapack (http://www.netlib.org/lapack/) libraries not found. Chris@87: Directories to search for the libraries can be specified in the Chris@87: numpy/distutils/site.cfg file (section [lapack]) or by setting Chris@87: the LAPACK environment variable.""" Chris@87: Chris@87: Chris@87: class LapackSrcNotFoundError(LapackNotFoundError): Chris@87: """ Chris@87: Lapack (http://www.netlib.org/lapack/) sources not found. Chris@87: Directories to search for the sources can be specified in the Chris@87: numpy/distutils/site.cfg file (section [lapack_src]) or by setting Chris@87: the LAPACK_SRC environment variable.""" Chris@87: Chris@87: Chris@87: class BlasNotFoundError(NotFoundError): Chris@87: """ Chris@87: Blas (http://www.netlib.org/blas/) libraries not found. Chris@87: Directories to search for the libraries can be specified in the Chris@87: numpy/distutils/site.cfg file (section [blas]) or by setting Chris@87: the BLAS environment variable.""" Chris@87: Chris@87: Chris@87: class BlasSrcNotFoundError(BlasNotFoundError): Chris@87: """ Chris@87: Blas (http://www.netlib.org/blas/) sources not found. Chris@87: Directories to search for the sources can be specified in the Chris@87: numpy/distutils/site.cfg file (section [blas_src]) or by setting Chris@87: the BLAS_SRC environment variable.""" Chris@87: Chris@87: Chris@87: class FFTWNotFoundError(NotFoundError): Chris@87: """ Chris@87: FFTW (http://www.fftw.org/) libraries not found. Chris@87: Directories to search for the libraries can be specified in the Chris@87: numpy/distutils/site.cfg file (section [fftw]) or by setting Chris@87: the FFTW environment variable.""" Chris@87: Chris@87: Chris@87: class DJBFFTNotFoundError(NotFoundError): Chris@87: """ Chris@87: DJBFFT (http://cr.yp.to/djbfft.html) libraries not found. Chris@87: Directories to search for the libraries can be specified in the Chris@87: numpy/distutils/site.cfg file (section [djbfft]) or by setting Chris@87: the DJBFFT environment variable.""" Chris@87: Chris@87: Chris@87: class NumericNotFoundError(NotFoundError): Chris@87: """ Chris@87: Numeric (http://www.numpy.org/) module not found. Chris@87: Get it from above location, install it, and retry setup.py.""" Chris@87: Chris@87: Chris@87: class X11NotFoundError(NotFoundError): Chris@87: """X11 libraries not found.""" Chris@87: Chris@87: Chris@87: class UmfpackNotFoundError(NotFoundError): Chris@87: """ Chris@87: UMFPACK sparse solver (http://www.cise.ufl.edu/research/sparse/umfpack/) Chris@87: not found. Directories to search for the libraries can be specified in the Chris@87: numpy/distutils/site.cfg file (section [umfpack]) or by setting Chris@87: the UMFPACK environment variable.""" Chris@87: Chris@87: Chris@87: class system_info: Chris@87: Chris@87: """ get_info() is the only public method. Don't use others. Chris@87: """ Chris@87: section = 'ALL' Chris@87: dir_env_var = None Chris@87: search_static_first = 0 # XXX: disabled by default, may disappear in Chris@87: # future unless it is proved to be useful. Chris@87: verbosity = 1 Chris@87: saved_results = {} Chris@87: Chris@87: notfounderror = NotFoundError Chris@87: Chris@87: def __init__(self, Chris@87: default_lib_dirs=default_lib_dirs, Chris@87: default_include_dirs=default_include_dirs, Chris@87: verbosity=1, Chris@87: ): Chris@87: self.__class__.info = {} Chris@87: self.local_prefixes = [] Chris@87: defaults = {} Chris@87: defaults['library_dirs'] = os.pathsep.join(default_lib_dirs) Chris@87: defaults['include_dirs'] = os.pathsep.join(default_include_dirs) Chris@87: defaults['src_dirs'] = os.pathsep.join(default_src_dirs) Chris@87: defaults['search_static_first'] = str(self.search_static_first) Chris@87: self.cp = ConfigParser(defaults) Chris@87: self.files = [] Chris@87: self.files.extend(get_standard_file('.numpy-site.cfg')) Chris@87: self.files.extend(get_standard_file('site.cfg')) Chris@87: self.parse_config_files() Chris@87: if self.section is not None: Chris@87: self.search_static_first = self.cp.getboolean( Chris@87: self.section, 'search_static_first') Chris@87: assert isinstance(self.search_static_first, int) Chris@87: Chris@87: def parse_config_files(self): Chris@87: self.cp.read(self.files) Chris@87: if not self.cp.has_section(self.section): Chris@87: if self.section is not None: Chris@87: self.cp.add_section(self.section) Chris@87: Chris@87: def calc_libraries_info(self): Chris@87: libs = self.get_libraries() Chris@87: dirs = self.get_lib_dirs() Chris@87: info = {} Chris@87: for lib in libs: Chris@87: i = self.check_libs(dirs, [lib]) Chris@87: if i is not None: Chris@87: dict_append(info, **i) Chris@87: else: Chris@87: log.info('Library %s was not found. Ignoring' % (lib)) Chris@87: return info Chris@87: Chris@87: def set_info(self, **info): Chris@87: if info: Chris@87: lib_info = self.calc_libraries_info() Chris@87: dict_append(info, **lib_info) Chris@87: self.saved_results[self.__class__.__name__] = info Chris@87: Chris@87: def has_info(self): Chris@87: return self.__class__.__name__ in self.saved_results Chris@87: Chris@87: def get_info(self, notfound_action=0): Chris@87: """ Return a dictonary with items that are compatible Chris@87: with numpy.distutils.setup keyword arguments. Chris@87: """ Chris@87: flag = 0 Chris@87: if not self.has_info(): Chris@87: flag = 1 Chris@87: log.info(self.__class__.__name__ + ':') Chris@87: if hasattr(self, 'calc_info'): Chris@87: self.calc_info() Chris@87: if notfound_action: Chris@87: if not self.has_info(): Chris@87: if notfound_action == 1: Chris@87: warnings.warn(self.notfounderror.__doc__) Chris@87: elif notfound_action == 2: Chris@87: raise self.notfounderror(self.notfounderror.__doc__) Chris@87: else: Chris@87: raise ValueError(repr(notfound_action)) Chris@87: Chris@87: if not self.has_info(): Chris@87: log.info(' NOT AVAILABLE') Chris@87: self.set_info() Chris@87: else: Chris@87: log.info(' FOUND:') Chris@87: Chris@87: res = self.saved_results.get(self.__class__.__name__) Chris@87: if self.verbosity > 0 and flag: Chris@87: for k, v in res.items(): Chris@87: v = str(v) Chris@87: if k in ['sources', 'libraries'] and len(v) > 270: Chris@87: v = v[:120] + '...\n...\n...' + v[-120:] Chris@87: log.info(' %s = %s', k, v) Chris@87: log.info('') Chris@87: Chris@87: return copy.deepcopy(res) Chris@87: Chris@87: def get_paths(self, section, key): Chris@87: dirs = self.cp.get(section, key).split(os.pathsep) Chris@87: env_var = self.dir_env_var Chris@87: if env_var: Chris@87: if is_sequence(env_var): Chris@87: e0 = env_var[-1] Chris@87: for e in env_var: Chris@87: if e in os.environ: Chris@87: e0 = e Chris@87: break Chris@87: if not env_var[0] == e0: Chris@87: log.info('Setting %s=%s' % (env_var[0], e0)) Chris@87: env_var = e0 Chris@87: if env_var and env_var in os.environ: Chris@87: d = os.environ[env_var] Chris@87: if d == 'None': Chris@87: log.info('Disabled %s: %s', Chris@87: self.__class__.__name__, '(%s is None)' Chris@87: % (env_var,)) Chris@87: return [] Chris@87: if os.path.isfile(d): Chris@87: dirs = [os.path.dirname(d)] + dirs Chris@87: l = getattr(self, '_lib_names', []) Chris@87: if len(l) == 1: Chris@87: b = os.path.basename(d) Chris@87: b = os.path.splitext(b)[0] Chris@87: if b[:3] == 'lib': Chris@87: log.info('Replacing _lib_names[0]==%r with %r' \ Chris@87: % (self._lib_names[0], b[3:])) Chris@87: self._lib_names[0] = b[3:] Chris@87: else: Chris@87: ds = d.split(os.pathsep) Chris@87: ds2 = [] Chris@87: for d in ds: Chris@87: if os.path.isdir(d): Chris@87: ds2.append(d) Chris@87: for dd in ['include', 'lib']: Chris@87: d1 = os.path.join(d, dd) Chris@87: if os.path.isdir(d1): Chris@87: ds2.append(d1) Chris@87: dirs = ds2 + dirs Chris@87: default_dirs = self.cp.get(self.section, key).split(os.pathsep) Chris@87: dirs.extend(default_dirs) Chris@87: ret = [] Chris@87: for d in dirs: Chris@87: if not os.path.isdir(d): Chris@87: warnings.warn('Specified path %s is invalid.' % d) Chris@87: continue Chris@87: Chris@87: if d not in ret: Chris@87: ret.append(d) Chris@87: Chris@87: log.debug('( %s = %s )', key, ':'.join(ret)) Chris@87: return ret Chris@87: Chris@87: def get_lib_dirs(self, key='library_dirs'): Chris@87: return self.get_paths(self.section, key) Chris@87: Chris@87: def get_include_dirs(self, key='include_dirs'): Chris@87: return self.get_paths(self.section, key) Chris@87: Chris@87: def get_src_dirs(self, key='src_dirs'): Chris@87: return self.get_paths(self.section, key) Chris@87: Chris@87: def get_libs(self, key, default): Chris@87: try: Chris@87: libs = self.cp.get(self.section, key) Chris@87: except NoOptionError: Chris@87: if not default: Chris@87: return [] Chris@87: if is_string(default): Chris@87: return [default] Chris@87: return default Chris@87: return [b for b in [a.strip() for a in libs.split(',')] if b] Chris@87: Chris@87: def get_libraries(self, key='libraries'): Chris@87: return self.get_libs(key, '') Chris@87: Chris@87: def library_extensions(self): Chris@87: static_exts = ['.a'] Chris@87: if sys.platform == 'win32': Chris@87: static_exts.append('.lib') # .lib is used by MSVC Chris@87: if self.search_static_first: Chris@87: exts = static_exts + [so_ext] Chris@87: else: Chris@87: exts = [so_ext] + static_exts Chris@87: if sys.platform == 'cygwin': Chris@87: exts.append('.dll.a') Chris@87: if sys.platform == 'darwin': Chris@87: exts.append('.dylib') Chris@87: # Debian and Ubuntu added a g3f suffix to shared library to deal with Chris@87: # g77 -> gfortran ABI transition Chris@87: # XXX: disabled, it hides more problem than it solves. Chris@87: #if sys.platform[:5] == 'linux': Chris@87: # exts.append('.so.3gf') Chris@87: return exts Chris@87: Chris@87: def check_libs(self, lib_dirs, libs, opt_libs=[]): Chris@87: """If static or shared libraries are available then return Chris@87: their info dictionary. Chris@87: Chris@87: Checks for all libraries as shared libraries first, then Chris@87: static (or vice versa if self.search_static_first is True). Chris@87: """ Chris@87: exts = self.library_extensions() Chris@87: info = None Chris@87: for ext in exts: Chris@87: info = self._check_libs(lib_dirs, libs, opt_libs, [ext]) Chris@87: if info is not None: Chris@87: break Chris@87: if not info: Chris@87: log.info(' libraries %s not found in %s', ','.join(libs), Chris@87: lib_dirs) Chris@87: return info Chris@87: Chris@87: def check_libs2(self, lib_dirs, libs, opt_libs=[]): Chris@87: """If static or shared libraries are available then return Chris@87: their info dictionary. Chris@87: Chris@87: Checks each library for shared or static. Chris@87: """ Chris@87: exts = self.library_extensions() Chris@87: info = self._check_libs(lib_dirs, libs, opt_libs, exts) Chris@87: if not info: Chris@87: log.info(' libraries %s not found in %s', ','.join(libs), Chris@87: lib_dirs) Chris@87: return info Chris@87: Chris@87: def _lib_list(self, lib_dir, libs, exts): Chris@87: assert is_string(lib_dir) Chris@87: liblist = [] Chris@87: # under windows first try without 'lib' prefix Chris@87: if sys.platform == 'win32': Chris@87: lib_prefixes = ['', 'lib'] Chris@87: else: Chris@87: lib_prefixes = ['lib'] Chris@87: # for each library name, see if we can find a file for it. Chris@87: for l in libs: Chris@87: for ext in exts: Chris@87: for prefix in lib_prefixes: Chris@87: p = self.combine_paths(lib_dir, prefix + l + ext) Chris@87: if p: Chris@87: break Chris@87: if p: Chris@87: assert len(p) == 1 Chris@87: # ??? splitext on p[0] would do this for cygwin Chris@87: # doesn't seem correct Chris@87: if ext == '.dll.a': Chris@87: l += '.dll' Chris@87: liblist.append(l) Chris@87: break Chris@87: return liblist Chris@87: Chris@87: def _check_libs(self, lib_dirs, libs, opt_libs, exts): Chris@87: """Find mandatory and optional libs in expected paths. Chris@87: Chris@87: Missing optional libraries are silently forgotten. Chris@87: """ Chris@87: # First, try to find the mandatory libraries Chris@87: if is_sequence(lib_dirs): Chris@87: found_libs, found_dirs = [], [] Chris@87: for dir_ in lib_dirs: Chris@87: found_libs1 = self._lib_list(dir_, libs, exts) Chris@87: # It's possible that we'll find the same library in multiple Chris@87: # directories. It's also possible that we'll find some Chris@87: # libraries on in directory, and some in another. So the Chris@87: # obvious thing would be to use a set instead of a list, but I Chris@87: # don't know if preserving order matters (does it?). Chris@87: for found_lib in found_libs1: Chris@87: if found_lib not in found_libs: Chris@87: found_libs.append(found_lib) Chris@87: if dir_ not in found_dirs: Chris@87: found_dirs.append(dir_) Chris@87: else: Chris@87: found_libs = self._lib_list(lib_dirs, libs, exts) Chris@87: found_dirs = [lib_dirs] Chris@87: if len(found_libs) > 0 and len(found_libs) == len(libs): Chris@87: info = {'libraries': found_libs, 'library_dirs': found_dirs} Chris@87: # Now, check for optional libraries Chris@87: if is_sequence(lib_dirs): Chris@87: for dir_ in lib_dirs: Chris@87: opt_found_libs = self._lib_list(dir_, opt_libs, exts) Chris@87: if opt_found_libs: Chris@87: if dir_ not in found_dirs: Chris@87: found_dirs.extend(dir_) Chris@87: found_libs.extend(opt_found_libs) Chris@87: else: Chris@87: opt_found_libs = self._lib_list(lib_dirs, opt_libs, exts) Chris@87: if opt_found_libs: Chris@87: found_libs.extend(opt_found_libs) Chris@87: return info Chris@87: else: Chris@87: return None Chris@87: Chris@87: def combine_paths(self, *args): Chris@87: """Return a list of existing paths composed by all combinations Chris@87: of items from the arguments. Chris@87: """ Chris@87: return combine_paths(*args, **{'verbosity': self.verbosity}) Chris@87: Chris@87: Chris@87: class fft_opt_info(system_info): Chris@87: Chris@87: def calc_info(self): Chris@87: info = {} Chris@87: fftw_info = get_info('fftw3') or get_info('fftw2') or get_info('dfftw') Chris@87: djbfft_info = get_info('djbfft') Chris@87: if fftw_info: Chris@87: dict_append(info, **fftw_info) Chris@87: if djbfft_info: Chris@87: dict_append(info, **djbfft_info) Chris@87: self.set_info(**info) Chris@87: return Chris@87: Chris@87: Chris@87: class fftw_info(system_info): Chris@87: #variables to override Chris@87: section = 'fftw' Chris@87: dir_env_var = 'FFTW' Chris@87: notfounderror = FFTWNotFoundError Chris@87: ver_info = [{'name':'fftw3', Chris@87: 'libs':['fftw3'], Chris@87: 'includes':['fftw3.h'], Chris@87: 'macros':[('SCIPY_FFTW3_H', None)]}, Chris@87: {'name':'fftw2', Chris@87: 'libs':['rfftw', 'fftw'], Chris@87: 'includes':['fftw.h', 'rfftw.h'], Chris@87: 'macros':[('SCIPY_FFTW_H', None)]}] Chris@87: Chris@87: def calc_ver_info(self, ver_param): Chris@87: """Returns True on successful version detection, else False""" Chris@87: lib_dirs = self.get_lib_dirs() Chris@87: incl_dirs = self.get_include_dirs() Chris@87: incl_dir = None Chris@87: libs = self.get_libs(self.section + '_libs', ver_param['libs']) Chris@87: info = self.check_libs(lib_dirs, libs) Chris@87: if info is not None: Chris@87: flag = 0 Chris@87: for d in incl_dirs: Chris@87: if len(self.combine_paths(d, ver_param['includes'])) \ Chris@87: == len(ver_param['includes']): Chris@87: dict_append(info, include_dirs=[d]) Chris@87: flag = 1 Chris@87: incl_dirs = [d] Chris@87: break Chris@87: if flag: Chris@87: dict_append(info, define_macros=ver_param['macros']) Chris@87: else: Chris@87: info = None Chris@87: if info is not None: Chris@87: self.set_info(**info) Chris@87: return True Chris@87: else: Chris@87: log.info(' %s not found' % (ver_param['name'])) Chris@87: return False Chris@87: Chris@87: def calc_info(self): Chris@87: for i in self.ver_info: Chris@87: if self.calc_ver_info(i): Chris@87: break Chris@87: Chris@87: Chris@87: class fftw2_info(fftw_info): Chris@87: #variables to override Chris@87: section = 'fftw' Chris@87: dir_env_var = 'FFTW' Chris@87: notfounderror = FFTWNotFoundError Chris@87: ver_info = [{'name':'fftw2', Chris@87: 'libs':['rfftw', 'fftw'], Chris@87: 'includes':['fftw.h', 'rfftw.h'], Chris@87: 'macros':[('SCIPY_FFTW_H', None)]} Chris@87: ] Chris@87: Chris@87: Chris@87: class fftw3_info(fftw_info): Chris@87: #variables to override Chris@87: section = 'fftw3' Chris@87: dir_env_var = 'FFTW3' Chris@87: notfounderror = FFTWNotFoundError Chris@87: ver_info = [{'name':'fftw3', Chris@87: 'libs':['fftw3'], Chris@87: 'includes':['fftw3.h'], Chris@87: 'macros':[('SCIPY_FFTW3_H', None)]}, Chris@87: ] Chris@87: Chris@87: Chris@87: class dfftw_info(fftw_info): Chris@87: section = 'fftw' Chris@87: dir_env_var = 'FFTW' Chris@87: ver_info = [{'name':'dfftw', Chris@87: 'libs':['drfftw', 'dfftw'], Chris@87: 'includes':['dfftw.h', 'drfftw.h'], Chris@87: 'macros':[('SCIPY_DFFTW_H', None)]}] Chris@87: Chris@87: Chris@87: class sfftw_info(fftw_info): Chris@87: section = 'fftw' Chris@87: dir_env_var = 'FFTW' Chris@87: ver_info = [{'name':'sfftw', Chris@87: 'libs':['srfftw', 'sfftw'], Chris@87: 'includes':['sfftw.h', 'srfftw.h'], Chris@87: 'macros':[('SCIPY_SFFTW_H', None)]}] Chris@87: Chris@87: Chris@87: class fftw_threads_info(fftw_info): Chris@87: section = 'fftw' Chris@87: dir_env_var = 'FFTW' Chris@87: ver_info = [{'name':'fftw threads', Chris@87: 'libs':['rfftw_threads', 'fftw_threads'], Chris@87: 'includes':['fftw_threads.h', 'rfftw_threads.h'], Chris@87: 'macros':[('SCIPY_FFTW_THREADS_H', None)]}] Chris@87: Chris@87: Chris@87: class dfftw_threads_info(fftw_info): Chris@87: section = 'fftw' Chris@87: dir_env_var = 'FFTW' Chris@87: ver_info = [{'name':'dfftw threads', Chris@87: 'libs':['drfftw_threads', 'dfftw_threads'], Chris@87: 'includes':['dfftw_threads.h', 'drfftw_threads.h'], Chris@87: 'macros':[('SCIPY_DFFTW_THREADS_H', None)]}] Chris@87: Chris@87: Chris@87: class sfftw_threads_info(fftw_info): Chris@87: section = 'fftw' Chris@87: dir_env_var = 'FFTW' Chris@87: ver_info = [{'name':'sfftw threads', Chris@87: 'libs':['srfftw_threads', 'sfftw_threads'], Chris@87: 'includes':['sfftw_threads.h', 'srfftw_threads.h'], Chris@87: 'macros':[('SCIPY_SFFTW_THREADS_H', None)]}] Chris@87: Chris@87: Chris@87: class djbfft_info(system_info): Chris@87: section = 'djbfft' Chris@87: dir_env_var = 'DJBFFT' Chris@87: notfounderror = DJBFFTNotFoundError Chris@87: Chris@87: def get_paths(self, section, key): Chris@87: pre_dirs = system_info.get_paths(self, section, key) Chris@87: dirs = [] Chris@87: for d in pre_dirs: Chris@87: dirs.extend(self.combine_paths(d, ['djbfft']) + [d]) Chris@87: return [d for d in dirs if os.path.isdir(d)] Chris@87: Chris@87: def calc_info(self): Chris@87: lib_dirs = self.get_lib_dirs() Chris@87: incl_dirs = self.get_include_dirs() Chris@87: info = None Chris@87: for d in lib_dirs: Chris@87: p = self.combine_paths(d, ['djbfft.a']) Chris@87: if p: Chris@87: info = {'extra_objects': p} Chris@87: break Chris@87: p = self.combine_paths(d, ['libdjbfft.a', 'libdjbfft' + so_ext]) Chris@87: if p: Chris@87: info = {'libraries': ['djbfft'], 'library_dirs': [d]} Chris@87: break Chris@87: if info is None: Chris@87: return Chris@87: for d in incl_dirs: Chris@87: if len(self.combine_paths(d, ['fftc8.h', 'fftfreq.h'])) == 2: Chris@87: dict_append(info, include_dirs=[d], Chris@87: define_macros=[('SCIPY_DJBFFT_H', None)]) Chris@87: self.set_info(**info) Chris@87: return Chris@87: return Chris@87: Chris@87: Chris@87: class mkl_info(system_info): Chris@87: section = 'mkl' Chris@87: dir_env_var = 'MKL' Chris@87: _lib_mkl = ['mkl', 'vml', 'guide'] Chris@87: Chris@87: def get_mkl_rootdir(self): Chris@87: mklroot = os.environ.get('MKLROOT', None) Chris@87: if mklroot is not None: Chris@87: return mklroot Chris@87: paths = os.environ.get('LD_LIBRARY_PATH', '').split(os.pathsep) Chris@87: ld_so_conf = '/etc/ld.so.conf' Chris@87: if os.path.isfile(ld_so_conf): Chris@87: for d in open(ld_so_conf, 'r'): Chris@87: d = d.strip() Chris@87: if d: Chris@87: paths.append(d) Chris@87: intel_mkl_dirs = [] Chris@87: for path in paths: Chris@87: path_atoms = path.split(os.sep) Chris@87: for m in path_atoms: Chris@87: if m.startswith('mkl'): Chris@87: d = os.sep.join(path_atoms[:path_atoms.index(m) + 2]) Chris@87: intel_mkl_dirs.append(d) Chris@87: break Chris@87: for d in paths: Chris@87: dirs = glob(os.path.join(d, 'mkl', '*')) Chris@87: dirs += glob(os.path.join(d, 'mkl*')) Chris@87: for d in dirs: Chris@87: if os.path.isdir(os.path.join(d, 'lib')): Chris@87: return d Chris@87: return None Chris@87: Chris@87: def __init__(self): Chris@87: mklroot = self.get_mkl_rootdir() Chris@87: if mklroot is None: Chris@87: system_info.__init__(self) Chris@87: else: Chris@87: from .cpuinfo import cpu Chris@87: l = 'mkl' # use shared library Chris@87: if cpu.is_Itanium(): Chris@87: plt = '64' Chris@87: #l = 'mkl_ipf' Chris@87: elif cpu.is_Xeon(): Chris@87: plt = 'em64t' Chris@87: #l = 'mkl_em64t' Chris@87: else: Chris@87: plt = '32' Chris@87: #l = 'mkl_ia32' Chris@87: if l not in self._lib_mkl: Chris@87: self._lib_mkl.insert(0, l) Chris@87: system_info.__init__( Chris@87: self, Chris@87: default_lib_dirs=[os.path.join(mklroot, 'lib', plt)], Chris@87: default_include_dirs=[os.path.join(mklroot, 'include')]) Chris@87: Chris@87: def calc_info(self): Chris@87: lib_dirs = self.get_lib_dirs() Chris@87: incl_dirs = self.get_include_dirs() Chris@87: mkl_libs = self.get_libs('mkl_libs', self._lib_mkl) Chris@87: info = self.check_libs2(lib_dirs, mkl_libs) Chris@87: if info is None: Chris@87: return Chris@87: dict_append(info, Chris@87: define_macros=[('SCIPY_MKL_H', None)], Chris@87: include_dirs=incl_dirs) Chris@87: if sys.platform == 'win32': Chris@87: pass # win32 has no pthread library Chris@87: else: Chris@87: dict_append(info, libraries=['pthread']) Chris@87: self.set_info(**info) Chris@87: Chris@87: Chris@87: class lapack_mkl_info(mkl_info): Chris@87: Chris@87: def calc_info(self): Chris@87: mkl = get_info('mkl') Chris@87: if not mkl: Chris@87: return Chris@87: if sys.platform == 'win32': Chris@87: lapack_libs = self.get_libs('lapack_libs', ['mkl_lapack']) Chris@87: else: Chris@87: lapack_libs = self.get_libs('lapack_libs', Chris@87: ['mkl_lapack32', 'mkl_lapack64']) Chris@87: Chris@87: info = {'libraries': lapack_libs} Chris@87: dict_append(info, **mkl) Chris@87: self.set_info(**info) Chris@87: Chris@87: Chris@87: class blas_mkl_info(mkl_info): Chris@87: pass Chris@87: Chris@87: Chris@87: class atlas_info(system_info): Chris@87: section = 'atlas' Chris@87: dir_env_var = 'ATLAS' Chris@87: _lib_names = ['f77blas', 'cblas'] Chris@87: if sys.platform[:7] == 'freebsd': Chris@87: _lib_atlas = ['atlas_r'] Chris@87: _lib_lapack = ['alapack_r'] Chris@87: else: Chris@87: _lib_atlas = ['atlas'] Chris@87: _lib_lapack = ['lapack'] Chris@87: Chris@87: notfounderror = AtlasNotFoundError Chris@87: Chris@87: def get_paths(self, section, key): Chris@87: pre_dirs = system_info.get_paths(self, section, key) Chris@87: dirs = [] Chris@87: for d in pre_dirs: Chris@87: dirs.extend(self.combine_paths(d, ['atlas*', 'ATLAS*', Chris@87: 'sse', '3dnow', 'sse2']) + [d]) Chris@87: return [d for d in dirs if os.path.isdir(d)] Chris@87: Chris@87: def calc_info(self): Chris@87: lib_dirs = self.get_lib_dirs() Chris@87: info = {} Chris@87: atlas_libs = self.get_libs('atlas_libs', Chris@87: self._lib_names + self._lib_atlas) Chris@87: lapack_libs = self.get_libs('lapack_libs', self._lib_lapack) Chris@87: atlas = None Chris@87: lapack = None Chris@87: atlas_1 = None Chris@87: for d in lib_dirs: Chris@87: atlas = self.check_libs2(d, atlas_libs, []) Chris@87: lapack_atlas = self.check_libs2(d, ['lapack_atlas'], []) Chris@87: if atlas is not None: Chris@87: lib_dirs2 = [d] + self.combine_paths(d, ['atlas*', 'ATLAS*']) Chris@87: lapack = self.check_libs2(lib_dirs2, lapack_libs, []) Chris@87: if lapack is not None: Chris@87: break Chris@87: if atlas: Chris@87: atlas_1 = atlas Chris@87: log.info(self.__class__) Chris@87: if atlas is None: Chris@87: atlas = atlas_1 Chris@87: if atlas is None: Chris@87: return Chris@87: include_dirs = self.get_include_dirs() Chris@87: h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None]) Chris@87: h = h[0] Chris@87: if h: Chris@87: h = os.path.dirname(h) Chris@87: dict_append(info, include_dirs=[h]) Chris@87: info['language'] = 'c' Chris@87: if lapack is not None: Chris@87: dict_append(info, **lapack) Chris@87: dict_append(info, **atlas) Chris@87: elif 'lapack_atlas' in atlas['libraries']: Chris@87: dict_append(info, **atlas) Chris@87: dict_append(info, Chris@87: define_macros=[('ATLAS_WITH_LAPACK_ATLAS', None)]) Chris@87: self.set_info(**info) Chris@87: return Chris@87: else: Chris@87: dict_append(info, **atlas) Chris@87: dict_append(info, define_macros=[('ATLAS_WITHOUT_LAPACK', None)]) Chris@87: message = """ Chris@87: ********************************************************************* Chris@87: Could not find lapack library within the ATLAS installation. Chris@87: ********************************************************************* Chris@87: """ Chris@87: warnings.warn(message) Chris@87: self.set_info(**info) Chris@87: return Chris@87: Chris@87: # Check if lapack library is complete, only warn if it is not. Chris@87: lapack_dir = lapack['library_dirs'][0] Chris@87: lapack_name = lapack['libraries'][0] Chris@87: lapack_lib = None Chris@87: lib_prefixes = ['lib'] Chris@87: if sys.platform == 'win32': Chris@87: lib_prefixes.append('') Chris@87: for e in self.library_extensions(): Chris@87: for prefix in lib_prefixes: Chris@87: fn = os.path.join(lapack_dir, prefix + lapack_name + e) Chris@87: if os.path.exists(fn): Chris@87: lapack_lib = fn Chris@87: break Chris@87: if lapack_lib: Chris@87: break Chris@87: if lapack_lib is not None: Chris@87: sz = os.stat(lapack_lib)[6] Chris@87: if sz <= 4000 * 1024: Chris@87: message = """ Chris@87: ********************************************************************* Chris@87: Lapack library (from ATLAS) is probably incomplete: Chris@87: size of %s is %sk (expected >4000k) Chris@87: Chris@87: Follow the instructions in the KNOWN PROBLEMS section of the file Chris@87: numpy/INSTALL.txt. Chris@87: ********************************************************************* Chris@87: """ % (lapack_lib, sz / 1024) Chris@87: warnings.warn(message) Chris@87: else: Chris@87: info['language'] = 'f77' Chris@87: Chris@87: atlas_version, atlas_extra_info = get_atlas_version(**atlas) Chris@87: dict_append(info, **atlas_extra_info) Chris@87: Chris@87: self.set_info(**info) Chris@87: Chris@87: Chris@87: class atlas_blas_info(atlas_info): Chris@87: _lib_names = ['f77blas', 'cblas'] Chris@87: Chris@87: def calc_info(self): Chris@87: lib_dirs = self.get_lib_dirs() Chris@87: info = {} Chris@87: atlas_libs = self.get_libs('atlas_libs', Chris@87: self._lib_names + self._lib_atlas) Chris@87: atlas = self.check_libs2(lib_dirs, atlas_libs, []) Chris@87: if atlas is None: Chris@87: return Chris@87: include_dirs = self.get_include_dirs() Chris@87: h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None]) Chris@87: h = h[0] Chris@87: if h: Chris@87: h = os.path.dirname(h) Chris@87: dict_append(info, include_dirs=[h]) Chris@87: info['language'] = 'c' Chris@87: Chris@87: atlas_version, atlas_extra_info = get_atlas_version(**atlas) Chris@87: dict_append(atlas, **atlas_extra_info) Chris@87: Chris@87: dict_append(info, **atlas) Chris@87: Chris@87: self.set_info(**info) Chris@87: return Chris@87: Chris@87: Chris@87: class atlas_threads_info(atlas_info): Chris@87: dir_env_var = ['PTATLAS', 'ATLAS'] Chris@87: _lib_names = ['ptf77blas', 'ptcblas'] Chris@87: Chris@87: Chris@87: class atlas_blas_threads_info(atlas_blas_info): Chris@87: dir_env_var = ['PTATLAS', 'ATLAS'] Chris@87: _lib_names = ['ptf77blas', 'ptcblas'] Chris@87: Chris@87: Chris@87: class lapack_atlas_info(atlas_info): Chris@87: _lib_names = ['lapack_atlas'] + atlas_info._lib_names Chris@87: Chris@87: Chris@87: class lapack_atlas_threads_info(atlas_threads_info): Chris@87: _lib_names = ['lapack_atlas'] + atlas_threads_info._lib_names Chris@87: Chris@87: Chris@87: class lapack_info(system_info): Chris@87: section = 'lapack' Chris@87: dir_env_var = 'LAPACK' Chris@87: _lib_names = ['lapack'] Chris@87: notfounderror = LapackNotFoundError Chris@87: Chris@87: def calc_info(self): Chris@87: lib_dirs = self.get_lib_dirs() Chris@87: Chris@87: lapack_libs = self.get_libs('lapack_libs', self._lib_names) Chris@87: info = self.check_libs(lib_dirs, lapack_libs, []) Chris@87: if info is None: Chris@87: return Chris@87: info['language'] = 'f77' Chris@87: self.set_info(**info) Chris@87: Chris@87: Chris@87: class lapack_src_info(system_info): Chris@87: section = 'lapack_src' Chris@87: dir_env_var = 'LAPACK_SRC' Chris@87: notfounderror = LapackSrcNotFoundError Chris@87: Chris@87: def get_paths(self, section, key): Chris@87: pre_dirs = system_info.get_paths(self, section, key) Chris@87: dirs = [] Chris@87: for d in pre_dirs: Chris@87: dirs.extend([d] + self.combine_paths(d, ['LAPACK*/SRC', 'SRC'])) Chris@87: return [d for d in dirs if os.path.isdir(d)] Chris@87: Chris@87: def calc_info(self): Chris@87: src_dirs = self.get_src_dirs() Chris@87: src_dir = '' Chris@87: for d in src_dirs: Chris@87: if os.path.isfile(os.path.join(d, 'dgesv.f')): Chris@87: src_dir = d Chris@87: break Chris@87: if not src_dir: Chris@87: #XXX: Get sources from netlib. May be ask first. Chris@87: return Chris@87: # The following is extracted from LAPACK-3.0/SRC/Makefile. Chris@87: # Added missing names from lapack-lite-3.1.1/SRC/Makefile Chris@87: # while keeping removed names for Lapack-3.0 compatibility. Chris@87: allaux = ''' Chris@87: ilaenv ieeeck lsame lsamen xerbla Chris@87: iparmq Chris@87: ''' # *.f Chris@87: laux = ''' Chris@87: bdsdc bdsqr disna labad lacpy ladiv lae2 laebz laed0 laed1 Chris@87: laed2 laed3 laed4 laed5 laed6 laed7 laed8 laed9 laeda laev2 Chris@87: lagtf lagts lamch lamrg lanst lapy2 lapy3 larnv larrb larre Chris@87: larrf lartg laruv las2 lascl lasd0 lasd1 lasd2 lasd3 lasd4 Chris@87: lasd5 lasd6 lasd7 lasd8 lasd9 lasda lasdq lasdt laset lasq1 Chris@87: lasq2 lasq3 lasq4 lasq5 lasq6 lasr lasrt lassq lasv2 pttrf Chris@87: stebz stedc steqr sterf Chris@87: Chris@87: larra larrc larrd larr larrk larrj larrr laneg laisnan isnan Chris@87: lazq3 lazq4 Chris@87: ''' # [s|d]*.f Chris@87: lasrc = ''' Chris@87: gbbrd gbcon gbequ gbrfs gbsv gbsvx gbtf2 gbtrf gbtrs gebak Chris@87: gebal gebd2 gebrd gecon geequ gees geesx geev geevx gegs gegv Chris@87: gehd2 gehrd gelq2 gelqf gels gelsd gelss gelsx gelsy geql2 Chris@87: geqlf geqp3 geqpf geqr2 geqrf gerfs gerq2 gerqf gesc2 gesdd Chris@87: gesv gesvd gesvx getc2 getf2 getrf getri getrs ggbak ggbal Chris@87: gges ggesx ggev ggevx ggglm gghrd gglse ggqrf ggrqf ggsvd Chris@87: ggsvp gtcon gtrfs gtsv gtsvx gttrf gttrs gtts2 hgeqz hsein Chris@87: hseqr labrd lacon laein lags2 lagtm lahqr lahrd laic1 lals0 Chris@87: lalsa lalsd langb lange langt lanhs lansb lansp lansy lantb Chris@87: lantp lantr lapll lapmt laqgb laqge laqp2 laqps laqsb laqsp Chris@87: laqsy lar1v lar2v larf larfb larfg larft larfx largv larrv Chris@87: lartv larz larzb larzt laswp lasyf latbs latdf latps latrd Chris@87: latrs latrz latzm lauu2 lauum pbcon pbequ pbrfs pbstf pbsv Chris@87: pbsvx pbtf2 pbtrf pbtrs pocon poequ porfs posv posvx potf2 Chris@87: potrf potri potrs ppcon ppequ pprfs ppsv ppsvx pptrf pptri Chris@87: pptrs ptcon pteqr ptrfs ptsv ptsvx pttrs ptts2 spcon sprfs Chris@87: spsv spsvx sptrf sptri sptrs stegr stein sycon syrfs sysv Chris@87: sysvx sytf2 sytrf sytri sytrs tbcon tbrfs tbtrs tgevc tgex2 Chris@87: tgexc tgsen tgsja tgsna tgsy2 tgsyl tpcon tprfs tptri tptrs Chris@87: trcon trevc trexc trrfs trsen trsna trsyl trti2 trtri trtrs Chris@87: tzrqf tzrzf Chris@87: Chris@87: lacn2 lahr2 stemr laqr0 laqr1 laqr2 laqr3 laqr4 laqr5 Chris@87: ''' # [s|c|d|z]*.f Chris@87: sd_lasrc = ''' Chris@87: laexc lag2 lagv2 laln2 lanv2 laqtr lasy2 opgtr opmtr org2l Chris@87: org2r orgbr orghr orgl2 orglq orgql orgqr orgr2 orgrq orgtr Chris@87: orm2l orm2r ormbr ormhr orml2 ormlq ormql ormqr ormr2 ormr3 Chris@87: ormrq ormrz ormtr rscl sbev sbevd sbevx sbgst sbgv sbgvd sbgvx Chris@87: sbtrd spev spevd spevx spgst spgv spgvd spgvx sptrd stev stevd Chris@87: stevr stevx syev syevd syevr syevx sygs2 sygst sygv sygvd Chris@87: sygvx sytd2 sytrd Chris@87: ''' # [s|d]*.f Chris@87: cz_lasrc = ''' Chris@87: bdsqr hbev hbevd hbevx hbgst hbgv hbgvd hbgvx hbtrd hecon heev Chris@87: heevd heevr heevx hegs2 hegst hegv hegvd hegvx herfs hesv Chris@87: hesvx hetd2 hetf2 hetrd hetrf hetri hetrs hpcon hpev hpevd Chris@87: hpevx hpgst hpgv hpgvd hpgvx hprfs hpsv hpsvx hptrd hptrf Chris@87: hptri hptrs lacgv lacp2 lacpy lacrm lacrt ladiv laed0 laed7 Chris@87: laed8 laesy laev2 lahef lanhb lanhe lanhp lanht laqhb laqhe Chris@87: laqhp larcm larnv lartg lascl laset lasr lassq pttrf rot spmv Chris@87: spr stedc steqr symv syr ung2l ung2r ungbr unghr ungl2 unglq Chris@87: ungql ungqr ungr2 ungrq ungtr unm2l unm2r unmbr unmhr unml2 Chris@87: unmlq unmql unmqr unmr2 unmr3 unmrq unmrz unmtr upgtr upmtr Chris@87: ''' # [c|z]*.f Chris@87: ####### Chris@87: sclaux = laux + ' econd ' # s*.f Chris@87: dzlaux = laux + ' secnd ' # d*.f Chris@87: slasrc = lasrc + sd_lasrc # s*.f Chris@87: dlasrc = lasrc + sd_lasrc # d*.f Chris@87: clasrc = lasrc + cz_lasrc + ' srot srscl ' # c*.f Chris@87: zlasrc = lasrc + cz_lasrc + ' drot drscl ' # z*.f Chris@87: oclasrc = ' icmax1 scsum1 ' # *.f Chris@87: ozlasrc = ' izmax1 dzsum1 ' # *.f Chris@87: sources = ['s%s.f' % f for f in (sclaux + slasrc).split()] \ Chris@87: + ['d%s.f' % f for f in (dzlaux + dlasrc).split()] \ Chris@87: + ['c%s.f' % f for f in (clasrc).split()] \ Chris@87: + ['z%s.f' % f for f in (zlasrc).split()] \ Chris@87: + ['%s.f' % f for f in (allaux + oclasrc + ozlasrc).split()] Chris@87: sources = [os.path.join(src_dir, f) for f in sources] Chris@87: # Lapack 3.1: Chris@87: src_dir2 = os.path.join(src_dir, '..', 'INSTALL') Chris@87: sources += [os.path.join(src_dir2, p + 'lamch.f') for p in 'sdcz'] Chris@87: # Lapack 3.2.1: Chris@87: sources += [os.path.join(src_dir, p + 'larfp.f') for p in 'sdcz'] Chris@87: sources += [os.path.join(src_dir, 'ila' + p + 'lr.f') for p in 'sdcz'] Chris@87: sources += [os.path.join(src_dir, 'ila' + p + 'lc.f') for p in 'sdcz'] Chris@87: # Should we check here actual existence of source files? Chris@87: # Yes, the file listing is different between 3.0 and 3.1 Chris@87: # versions. Chris@87: sources = [f for f in sources if os.path.isfile(f)] Chris@87: info = {'sources': sources, 'language': 'f77'} Chris@87: self.set_info(**info) Chris@87: Chris@87: atlas_version_c_text = r''' Chris@87: /* This file is generated from numpy/distutils/system_info.py */ Chris@87: void ATL_buildinfo(void); Chris@87: int main(void) { Chris@87: ATL_buildinfo(); Chris@87: return 0; Chris@87: } Chris@87: ''' Chris@87: Chris@87: _cached_atlas_version = {} Chris@87: Chris@87: Chris@87: def get_atlas_version(**config): Chris@87: libraries = config.get('libraries', []) Chris@87: library_dirs = config.get('library_dirs', []) Chris@87: key = (tuple(libraries), tuple(library_dirs)) Chris@87: if key in _cached_atlas_version: Chris@87: return _cached_atlas_version[key] Chris@87: c = cmd_config(Distribution()) Chris@87: atlas_version = None Chris@87: info = {} Chris@87: try: Chris@87: s, o = c.get_output(atlas_version_c_text, Chris@87: libraries=libraries, library_dirs=library_dirs, Chris@87: use_tee=(system_info.verbosity > 0)) Chris@87: if s and re.search(r'undefined reference to `_gfortran', o, re.M): Chris@87: s, o = c.get_output(atlas_version_c_text, Chris@87: libraries=libraries + ['gfortran'], Chris@87: library_dirs=library_dirs, Chris@87: use_tee=(system_info.verbosity > 0)) Chris@87: if not s: Chris@87: warnings.warn(""" Chris@87: ***************************************************** Chris@87: Linkage with ATLAS requires gfortran. Use Chris@87: Chris@87: python setup.py config_fc --fcompiler=gnu95 ... Chris@87: Chris@87: when building extension libraries that use ATLAS. Chris@87: Make sure that -lgfortran is used for C++ extensions. Chris@87: ***************************************************** Chris@87: """) Chris@87: dict_append(info, language='f90', Chris@87: define_macros=[('ATLAS_REQUIRES_GFORTRAN', None)]) Chris@87: except Exception: # failed to get version from file -- maybe on Windows Chris@87: # look at directory name Chris@87: for o in library_dirs: Chris@87: m = re.search(r'ATLAS_(?P\d+[.]\d+[.]\d+)_', o) Chris@87: if m: Chris@87: atlas_version = m.group('version') Chris@87: if atlas_version is not None: Chris@87: break Chris@87: Chris@87: # final choice --- look at ATLAS_VERSION environment Chris@87: # variable Chris@87: if atlas_version is None: Chris@87: atlas_version = os.environ.get('ATLAS_VERSION', None) Chris@87: if atlas_version: Chris@87: dict_append(info, define_macros=[( Chris@87: 'ATLAS_INFO', '"\\"%s\\""' % atlas_version) Chris@87: ]) Chris@87: else: Chris@87: dict_append(info, define_macros=[('NO_ATLAS_INFO', -1)]) Chris@87: return atlas_version or '?.?.?', info Chris@87: Chris@87: if not s: Chris@87: m = re.search(r'ATLAS version (?P\d+[.]\d+[.]\d+)', o) Chris@87: if m: Chris@87: atlas_version = m.group('version') Chris@87: if atlas_version is None: Chris@87: if re.search(r'undefined symbol: ATL_buildinfo', o, re.M): Chris@87: atlas_version = '3.2.1_pre3.3.6' Chris@87: else: Chris@87: log.info('Status: %d', s) Chris@87: log.info('Output: %s', o) Chris@87: Chris@87: if atlas_version == '3.2.1_pre3.3.6': Chris@87: dict_append(info, define_macros=[('NO_ATLAS_INFO', -2)]) Chris@87: else: Chris@87: dict_append(info, define_macros=[( Chris@87: 'ATLAS_INFO', '"\\"%s\\""' % atlas_version) Chris@87: ]) Chris@87: result = _cached_atlas_version[key] = atlas_version, info Chris@87: return result Chris@87: Chris@87: Chris@87: Chris@87: class lapack_opt_info(system_info): Chris@87: Chris@87: notfounderror = LapackNotFoundError Chris@87: Chris@87: def calc_info(self): Chris@87: Chris@87: openblas_info = get_info('openblas_lapack') Chris@87: if openblas_info: Chris@87: self.set_info(**openblas_info) Chris@87: return Chris@87: Chris@87: lapack_mkl_info = get_info('lapack_mkl') Chris@87: if lapack_mkl_info: Chris@87: self.set_info(**lapack_mkl_info) Chris@87: return Chris@87: Chris@87: atlas_info = get_info('atlas_threads') Chris@87: if not atlas_info: Chris@87: atlas_info = get_info('atlas') Chris@87: Chris@87: if sys.platform == 'darwin' and not atlas_info: Chris@87: # Use the system lapack from Accelerate or vecLib under OSX Chris@87: args = [] Chris@87: link_args = [] Chris@87: if get_platform()[-4:] == 'i386' or 'intel' in get_platform() or \ Chris@87: 'x86_64' in get_platform() or \ Chris@87: 'i386' in platform.platform(): Chris@87: intel = 1 Chris@87: else: Chris@87: intel = 0 Chris@87: if os.path.exists('/System/Library/Frameworks' Chris@87: '/Accelerate.framework/'): Chris@87: if intel: Chris@87: args.extend(['-msse3', '-DAPPLE_ACCELERATE_SGEMV_PATCH']) Chris@87: else: Chris@87: args.extend(['-faltivec']) Chris@87: link_args.extend(['-Wl,-framework', '-Wl,Accelerate']) Chris@87: elif os.path.exists('/System/Library/Frameworks' Chris@87: '/vecLib.framework/'): Chris@87: if intel: Chris@87: args.extend(['-msse3']) Chris@87: else: Chris@87: args.extend(['-faltivec']) Chris@87: link_args.extend(['-Wl,-framework', '-Wl,vecLib']) Chris@87: if args: Chris@87: self.set_info(extra_compile_args=args, Chris@87: extra_link_args=link_args, Chris@87: define_macros=[('NO_ATLAS_INFO', 3)]) Chris@87: return Chris@87: Chris@87: #atlas_info = {} ## uncomment for testing Chris@87: need_lapack = 0 Chris@87: need_blas = 0 Chris@87: info = {} Chris@87: if atlas_info: Chris@87: l = atlas_info.get('define_macros', []) Chris@87: if ('ATLAS_WITH_LAPACK_ATLAS', None) in l \ Chris@87: or ('ATLAS_WITHOUT_LAPACK', None) in l: Chris@87: need_lapack = 1 Chris@87: info = atlas_info Chris@87: Chris@87: else: Chris@87: warnings.warn(AtlasNotFoundError.__doc__) Chris@87: need_blas = 1 Chris@87: need_lapack = 1 Chris@87: dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) Chris@87: Chris@87: if need_lapack: Chris@87: lapack_info = get_info('lapack') Chris@87: #lapack_info = {} ## uncomment for testing Chris@87: if lapack_info: Chris@87: dict_append(info, **lapack_info) Chris@87: else: Chris@87: warnings.warn(LapackNotFoundError.__doc__) Chris@87: lapack_src_info = get_info('lapack_src') Chris@87: if not lapack_src_info: Chris@87: warnings.warn(LapackSrcNotFoundError.__doc__) Chris@87: return Chris@87: dict_append(info, libraries=[('flapack_src', lapack_src_info)]) Chris@87: Chris@87: if need_blas: Chris@87: blas_info = get_info('blas') Chris@87: #blas_info = {} ## uncomment for testing Chris@87: if blas_info: Chris@87: dict_append(info, **blas_info) Chris@87: else: Chris@87: warnings.warn(BlasNotFoundError.__doc__) Chris@87: blas_src_info = get_info('blas_src') Chris@87: if not blas_src_info: Chris@87: warnings.warn(BlasSrcNotFoundError.__doc__) Chris@87: return Chris@87: dict_append(info, libraries=[('fblas_src', blas_src_info)]) Chris@87: Chris@87: self.set_info(**info) Chris@87: return Chris@87: Chris@87: Chris@87: class blas_opt_info(system_info): Chris@87: Chris@87: notfounderror = BlasNotFoundError Chris@87: Chris@87: def calc_info(self): Chris@87: Chris@87: blas_mkl_info = get_info('blas_mkl') Chris@87: if blas_mkl_info: Chris@87: self.set_info(**blas_mkl_info) Chris@87: return Chris@87: Chris@87: openblas_info = get_info('openblas') Chris@87: if openblas_info: Chris@87: self.set_info(**openblas_info) Chris@87: return Chris@87: Chris@87: atlas_info = get_info('atlas_blas_threads') Chris@87: if not atlas_info: Chris@87: atlas_info = get_info('atlas_blas') Chris@87: Chris@87: if sys.platform == 'darwin' and not atlas_info: Chris@87: # Use the system BLAS from Accelerate or vecLib under OSX Chris@87: args = [] Chris@87: link_args = [] Chris@87: if get_platform()[-4:] == 'i386' or 'intel' in get_platform() or \ Chris@87: 'x86_64' in get_platform() or \ Chris@87: 'i386' in platform.platform(): Chris@87: intel = 1 Chris@87: else: Chris@87: intel = 0 Chris@87: if os.path.exists('/System/Library/Frameworks' Chris@87: '/Accelerate.framework/'): Chris@87: if intel: Chris@87: args.extend(['-msse3', '-DAPPLE_ACCELERATE_SGEMV_PATCH']) Chris@87: else: Chris@87: args.extend(['-faltivec']) Chris@87: args.extend([ Chris@87: '-I/System/Library/Frameworks/vecLib.framework/Headers']) Chris@87: link_args.extend(['-Wl,-framework', '-Wl,Accelerate']) Chris@87: elif os.path.exists('/System/Library/Frameworks' Chris@87: '/vecLib.framework/'): Chris@87: if intel: Chris@87: args.extend(['-msse3']) Chris@87: else: Chris@87: args.extend(['-faltivec']) Chris@87: args.extend([ Chris@87: '-I/System/Library/Frameworks/vecLib.framework/Headers']) Chris@87: link_args.extend(['-Wl,-framework', '-Wl,vecLib']) Chris@87: if args: Chris@87: self.set_info(extra_compile_args=args, Chris@87: extra_link_args=link_args, Chris@87: define_macros=[('NO_ATLAS_INFO', 3)]) Chris@87: return Chris@87: Chris@87: need_blas = 0 Chris@87: info = {} Chris@87: if atlas_info: Chris@87: info = atlas_info Chris@87: else: Chris@87: warnings.warn(AtlasNotFoundError.__doc__) Chris@87: need_blas = 1 Chris@87: dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) Chris@87: Chris@87: if need_blas: Chris@87: blas_info = get_info('blas') Chris@87: if blas_info: Chris@87: dict_append(info, **blas_info) Chris@87: else: Chris@87: warnings.warn(BlasNotFoundError.__doc__) Chris@87: blas_src_info = get_info('blas_src') Chris@87: if not blas_src_info: Chris@87: warnings.warn(BlasSrcNotFoundError.__doc__) Chris@87: return Chris@87: dict_append(info, libraries=[('fblas_src', blas_src_info)]) Chris@87: Chris@87: self.set_info(**info) Chris@87: return Chris@87: Chris@87: Chris@87: class blas_info(system_info): Chris@87: section = 'blas' Chris@87: dir_env_var = 'BLAS' Chris@87: _lib_names = ['blas'] Chris@87: notfounderror = BlasNotFoundError Chris@87: Chris@87: def calc_info(self): Chris@87: lib_dirs = self.get_lib_dirs() Chris@87: Chris@87: blas_libs = self.get_libs('blas_libs', self._lib_names) Chris@87: info = self.check_libs(lib_dirs, blas_libs, []) Chris@87: if info is None: Chris@87: return Chris@87: info['language'] = 'f77' # XXX: is it generally true? Chris@87: self.set_info(**info) Chris@87: Chris@87: Chris@87: class openblas_info(blas_info): Chris@87: section = 'openblas' Chris@87: dir_env_var = 'OPENBLAS' Chris@87: _lib_names = ['openblas'] Chris@87: notfounderror = BlasNotFoundError Chris@87: Chris@87: def check_embedded_lapack(self, info): Chris@87: return True Chris@87: Chris@87: def calc_info(self): Chris@87: lib_dirs = self.get_lib_dirs() Chris@87: Chris@87: openblas_libs = self.get_libs('libraries', self._lib_names) Chris@87: if openblas_libs == self._lib_names: # backward compat with 1.8.0 Chris@87: openblas_libs = self.get_libs('openblas_libs', self._lib_names) Chris@87: info = self.check_libs(lib_dirs, openblas_libs, []) Chris@87: if info is None: Chris@87: return Chris@87: Chris@87: if not self.check_embedded_lapack(info): Chris@87: return None Chris@87: Chris@87: info['language'] = 'f77' # XXX: is it generally true? Chris@87: self.set_info(**info) Chris@87: Chris@87: Chris@87: class openblas_lapack_info(openblas_info): Chris@87: section = 'openblas' Chris@87: dir_env_var = 'OPENBLAS' Chris@87: _lib_names = ['openblas'] Chris@87: notfounderror = BlasNotFoundError Chris@87: Chris@87: def check_embedded_lapack(self, info): Chris@87: res = False Chris@87: c = distutils.ccompiler.new_compiler() Chris@87: tmpdir = tempfile.mkdtemp() Chris@87: s = """void zungqr(); Chris@87: int main(int argc, const char *argv[]) Chris@87: { Chris@87: zungqr_(); Chris@87: return 0; Chris@87: }""" Chris@87: src = os.path.join(tmpdir, 'source.c') Chris@87: out = os.path.join(tmpdir, 'a.out') Chris@87: try: Chris@87: with open(src, 'wt') as f: Chris@87: f.write(s) Chris@87: obj = c.compile([src], output_dir=tmpdir) Chris@87: try: Chris@87: c.link_executable(obj, out, libraries=info['libraries'], Chris@87: library_dirs=info['library_dirs']) Chris@87: res = True Chris@87: except distutils.ccompiler.LinkError: Chris@87: res = False Chris@87: finally: Chris@87: shutil.rmtree(tmpdir) Chris@87: return res Chris@87: Chris@87: Chris@87: class blas_src_info(system_info): Chris@87: section = 'blas_src' Chris@87: dir_env_var = 'BLAS_SRC' Chris@87: notfounderror = BlasSrcNotFoundError Chris@87: Chris@87: def get_paths(self, section, key): Chris@87: pre_dirs = system_info.get_paths(self, section, key) Chris@87: dirs = [] Chris@87: for d in pre_dirs: Chris@87: dirs.extend([d] + self.combine_paths(d, ['blas'])) Chris@87: return [d for d in dirs if os.path.isdir(d)] Chris@87: Chris@87: def calc_info(self): Chris@87: src_dirs = self.get_src_dirs() Chris@87: src_dir = '' Chris@87: for d in src_dirs: Chris@87: if os.path.isfile(os.path.join(d, 'daxpy.f')): Chris@87: src_dir = d Chris@87: break Chris@87: if not src_dir: Chris@87: #XXX: Get sources from netlib. May be ask first. Chris@87: return Chris@87: blas1 = ''' Chris@87: caxpy csscal dnrm2 dzasum saxpy srotg zdotc ccopy cswap drot Chris@87: dznrm2 scasum srotm zdotu cdotc dasum drotg icamax scnrm2 Chris@87: srotmg zdrot cdotu daxpy drotm idamax scopy sscal zdscal crotg Chris@87: dcabs1 drotmg isamax sdot sswap zrotg cscal dcopy dscal izamax Chris@87: snrm2 zaxpy zscal csrot ddot dswap sasum srot zcopy zswap Chris@87: scabs1 Chris@87: ''' Chris@87: blas2 = ''' Chris@87: cgbmv chpmv ctrsv dsymv dtrsv sspr2 strmv zhemv ztpmv cgemv Chris@87: chpr dgbmv dsyr lsame ssymv strsv zher ztpsv cgerc chpr2 dgemv Chris@87: dsyr2 sgbmv ssyr xerbla zher2 ztrmv cgeru ctbmv dger dtbmv Chris@87: sgemv ssyr2 zgbmv zhpmv ztrsv chbmv ctbsv dsbmv dtbsv sger Chris@87: stbmv zgemv zhpr chemv ctpmv dspmv dtpmv ssbmv stbsv zgerc Chris@87: zhpr2 cher ctpsv dspr dtpsv sspmv stpmv zgeru ztbmv cher2 Chris@87: ctrmv dspr2 dtrmv sspr stpsv zhbmv ztbsv Chris@87: ''' Chris@87: blas3 = ''' Chris@87: cgemm csymm ctrsm dsyrk sgemm strmm zhemm zsyr2k chemm csyr2k Chris@87: dgemm dtrmm ssymm strsm zher2k zsyrk cher2k csyrk dsymm dtrsm Chris@87: ssyr2k zherk ztrmm cherk ctrmm dsyr2k ssyrk zgemm zsymm ztrsm Chris@87: ''' Chris@87: sources = [os.path.join(src_dir, f + '.f') \ Chris@87: for f in (blas1 + blas2 + blas3).split()] Chris@87: #XXX: should we check here actual existence of source files? Chris@87: sources = [f for f in sources if os.path.isfile(f)] Chris@87: info = {'sources': sources, 'language': 'f77'} Chris@87: self.set_info(**info) Chris@87: Chris@87: Chris@87: class x11_info(system_info): Chris@87: section = 'x11' Chris@87: notfounderror = X11NotFoundError Chris@87: Chris@87: def __init__(self): Chris@87: system_info.__init__(self, Chris@87: default_lib_dirs=default_x11_lib_dirs, Chris@87: default_include_dirs=default_x11_include_dirs) Chris@87: Chris@87: def calc_info(self): Chris@87: if sys.platform in ['win32']: Chris@87: return Chris@87: lib_dirs = self.get_lib_dirs() Chris@87: include_dirs = self.get_include_dirs() Chris@87: x11_libs = self.get_libs('x11_libs', ['X11']) Chris@87: info = self.check_libs(lib_dirs, x11_libs, []) Chris@87: if info is None: Chris@87: return Chris@87: inc_dir = None Chris@87: for d in include_dirs: Chris@87: if self.combine_paths(d, 'X11/X.h'): Chris@87: inc_dir = d Chris@87: break Chris@87: if inc_dir is not None: Chris@87: dict_append(info, include_dirs=[inc_dir]) Chris@87: self.set_info(**info) Chris@87: Chris@87: Chris@87: class _numpy_info(system_info): Chris@87: section = 'Numeric' Chris@87: modulename = 'Numeric' Chris@87: notfounderror = NumericNotFoundError Chris@87: Chris@87: def __init__(self): Chris@87: include_dirs = [] Chris@87: try: Chris@87: module = __import__(self.modulename) Chris@87: prefix = [] Chris@87: for name in module.__file__.split(os.sep): Chris@87: if name == 'lib': Chris@87: break Chris@87: prefix.append(name) Chris@87: Chris@87: # Ask numpy for its own include path before attempting Chris@87: # anything else Chris@87: try: Chris@87: include_dirs.append(getattr(module, 'get_include')()) Chris@87: except AttributeError: Chris@87: pass Chris@87: Chris@87: include_dirs.append(distutils.sysconfig.get_python_inc( Chris@87: prefix=os.sep.join(prefix))) Chris@87: except ImportError: Chris@87: pass Chris@87: py_incl_dir = distutils.sysconfig.get_python_inc() Chris@87: include_dirs.append(py_incl_dir) Chris@87: py_pincl_dir = distutils.sysconfig.get_python_inc(plat_specific=True) Chris@87: if py_pincl_dir not in include_dirs: Chris@87: include_dirs.append(py_pincl_dir) Chris@87: for d in default_include_dirs: Chris@87: d = os.path.join(d, os.path.basename(py_incl_dir)) Chris@87: if d not in include_dirs: Chris@87: include_dirs.append(d) Chris@87: system_info.__init__(self, Chris@87: default_lib_dirs=[], Chris@87: default_include_dirs=include_dirs) Chris@87: Chris@87: def calc_info(self): Chris@87: try: Chris@87: module = __import__(self.modulename) Chris@87: except ImportError: Chris@87: return Chris@87: info = {} Chris@87: macros = [] Chris@87: for v in ['__version__', 'version']: Chris@87: vrs = getattr(module, v, None) Chris@87: if vrs is None: Chris@87: continue Chris@87: macros = [(self.modulename.upper() + '_VERSION', Chris@87: '"\\"%s\\""' % (vrs)), Chris@87: (self.modulename.upper(), None)] Chris@87: break Chris@87: ## try: Chris@87: ## macros.append( Chris@87: ## (self.modulename.upper()+'_VERSION_HEX', Chris@87: ## hex(vstr2hex(module.__version__))), Chris@87: ## ) Chris@87: ## except Exception as msg: Chris@87: ## print msg Chris@87: dict_append(info, define_macros=macros) Chris@87: include_dirs = self.get_include_dirs() Chris@87: inc_dir = None Chris@87: for d in include_dirs: Chris@87: if self.combine_paths(d, Chris@87: os.path.join(self.modulename, Chris@87: 'arrayobject.h')): Chris@87: inc_dir = d Chris@87: break Chris@87: if inc_dir is not None: Chris@87: dict_append(info, include_dirs=[inc_dir]) Chris@87: if info: Chris@87: self.set_info(**info) Chris@87: return Chris@87: Chris@87: Chris@87: class numarray_info(_numpy_info): Chris@87: section = 'numarray' Chris@87: modulename = 'numarray' Chris@87: Chris@87: Chris@87: class Numeric_info(_numpy_info): Chris@87: section = 'Numeric' Chris@87: modulename = 'Numeric' Chris@87: Chris@87: Chris@87: class numpy_info(_numpy_info): Chris@87: section = 'numpy' Chris@87: modulename = 'numpy' Chris@87: Chris@87: Chris@87: class numerix_info(system_info): Chris@87: section = 'numerix' Chris@87: Chris@87: def calc_info(self): Chris@87: which = None, None Chris@87: if os.getenv("NUMERIX"): Chris@87: which = os.getenv("NUMERIX"), "environment var" Chris@87: # If all the above fail, default to numpy. Chris@87: if which[0] is None: Chris@87: which = "numpy", "defaulted" Chris@87: try: Chris@87: import numpy Chris@87: which = "numpy", "defaulted" Chris@87: except ImportError: Chris@87: msg1 = str(get_exception()) Chris@87: try: Chris@87: import Numeric Chris@87: which = "numeric", "defaulted" Chris@87: except ImportError: Chris@87: msg2 = str(get_exception()) Chris@87: try: Chris@87: import numarray Chris@87: which = "numarray", "defaulted" Chris@87: except ImportError: Chris@87: msg3 = str(get_exception()) Chris@87: log.info(msg1) Chris@87: log.info(msg2) Chris@87: log.info(msg3) Chris@87: which = which[0].strip().lower(), which[1] Chris@87: if which[0] not in ["numeric", "numarray", "numpy"]: Chris@87: raise ValueError("numerix selector must be either 'Numeric' " Chris@87: "or 'numarray' or 'numpy' but the value obtained" Chris@87: " from the %s was '%s'." % (which[1], which[0])) Chris@87: os.environ['NUMERIX'] = which[0] Chris@87: self.set_info(**get_info(which[0])) Chris@87: Chris@87: Chris@87: class f2py_info(system_info): Chris@87: def calc_info(self): Chris@87: try: Chris@87: import numpy.f2py as f2py Chris@87: except ImportError: Chris@87: return Chris@87: f2py_dir = os.path.join(os.path.dirname(f2py.__file__), 'src') Chris@87: self.set_info(sources=[os.path.join(f2py_dir, 'fortranobject.c')], Chris@87: include_dirs=[f2py_dir]) Chris@87: return Chris@87: Chris@87: Chris@87: class boost_python_info(system_info): Chris@87: section = 'boost_python' Chris@87: dir_env_var = 'BOOST' Chris@87: Chris@87: def get_paths(self, section, key): Chris@87: pre_dirs = system_info.get_paths(self, section, key) Chris@87: dirs = [] Chris@87: for d in pre_dirs: Chris@87: dirs.extend([d] + self.combine_paths(d, ['boost*'])) Chris@87: return [d for d in dirs if os.path.isdir(d)] Chris@87: Chris@87: def calc_info(self): Chris@87: src_dirs = self.get_src_dirs() Chris@87: src_dir = '' Chris@87: for d in src_dirs: Chris@87: if os.path.isfile(os.path.join(d, 'libs', 'python', 'src', Chris@87: 'module.cpp')): Chris@87: src_dir = d Chris@87: break Chris@87: if not src_dir: Chris@87: return Chris@87: py_incl_dirs = [distutils.sysconfig.get_python_inc()] Chris@87: py_pincl_dir = distutils.sysconfig.get_python_inc(plat_specific=True) Chris@87: if py_pincl_dir not in py_incl_dirs: Chris@87: py_incl_dirs.append(py_pincl_dir) Chris@87: srcs_dir = os.path.join(src_dir, 'libs', 'python', 'src') Chris@87: bpl_srcs = glob(os.path.join(srcs_dir, '*.cpp')) Chris@87: bpl_srcs += glob(os.path.join(srcs_dir, '*', '*.cpp')) Chris@87: info = {'libraries': [('boost_python_src', Chris@87: {'include_dirs': [src_dir] + py_incl_dirs, Chris@87: 'sources':bpl_srcs} Chris@87: )], Chris@87: 'include_dirs': [src_dir], Chris@87: } Chris@87: if info: Chris@87: self.set_info(**info) Chris@87: return Chris@87: Chris@87: Chris@87: class agg2_info(system_info): Chris@87: section = 'agg2' Chris@87: dir_env_var = 'AGG2' Chris@87: Chris@87: def get_paths(self, section, key): Chris@87: pre_dirs = system_info.get_paths(self, section, key) Chris@87: dirs = [] Chris@87: for d in pre_dirs: Chris@87: dirs.extend([d] + self.combine_paths(d, ['agg2*'])) Chris@87: return [d for d in dirs if os.path.isdir(d)] Chris@87: Chris@87: def calc_info(self): Chris@87: src_dirs = self.get_src_dirs() Chris@87: src_dir = '' Chris@87: for d in src_dirs: Chris@87: if os.path.isfile(os.path.join(d, 'src', 'agg_affine_matrix.cpp')): Chris@87: src_dir = d Chris@87: break Chris@87: if not src_dir: Chris@87: return Chris@87: if sys.platform == 'win32': Chris@87: agg2_srcs = glob(os.path.join(src_dir, 'src', 'platform', Chris@87: 'win32', 'agg_win32_bmp.cpp')) Chris@87: else: Chris@87: agg2_srcs = glob(os.path.join(src_dir, 'src', '*.cpp')) Chris@87: agg2_srcs += [os.path.join(src_dir, 'src', 'platform', Chris@87: 'X11', Chris@87: 'agg_platform_support.cpp')] Chris@87: Chris@87: info = {'libraries': Chris@87: [('agg2_src', Chris@87: {'sources': agg2_srcs, Chris@87: 'include_dirs': [os.path.join(src_dir, 'include')], Chris@87: } Chris@87: )], Chris@87: 'include_dirs': [os.path.join(src_dir, 'include')], Chris@87: } Chris@87: if info: Chris@87: self.set_info(**info) Chris@87: return Chris@87: Chris@87: Chris@87: class _pkg_config_info(system_info): Chris@87: section = None Chris@87: config_env_var = 'PKG_CONFIG' Chris@87: default_config_exe = 'pkg-config' Chris@87: append_config_exe = '' Chris@87: version_macro_name = None Chris@87: release_macro_name = None Chris@87: version_flag = '--modversion' Chris@87: cflags_flag = '--cflags' Chris@87: Chris@87: def get_config_exe(self): Chris@87: if self.config_env_var in os.environ: Chris@87: return os.environ[self.config_env_var] Chris@87: return self.default_config_exe Chris@87: Chris@87: def get_config_output(self, config_exe, option): Chris@87: cmd = config_exe + ' ' + self.append_config_exe + ' ' + option Chris@87: s, o = exec_command(cmd, use_tee=0) Chris@87: if not s: Chris@87: return o Chris@87: Chris@87: def calc_info(self): Chris@87: config_exe = find_executable(self.get_config_exe()) Chris@87: if not config_exe: Chris@87: log.warn('File not found: %s. Cannot determine %s info.' \ Chris@87: % (config_exe, self.section)) Chris@87: return Chris@87: info = {} Chris@87: macros = [] Chris@87: libraries = [] Chris@87: library_dirs = [] Chris@87: include_dirs = [] Chris@87: extra_link_args = [] Chris@87: extra_compile_args = [] Chris@87: version = self.get_config_output(config_exe, self.version_flag) Chris@87: if version: Chris@87: macros.append((self.__class__.__name__.split('.')[-1].upper(), Chris@87: '"\\"%s\\""' % (version))) Chris@87: if self.version_macro_name: Chris@87: macros.append((self.version_macro_name + '_%s' Chris@87: % (version.replace('.', '_')), None)) Chris@87: if self.release_macro_name: Chris@87: release = self.get_config_output(config_exe, '--release') Chris@87: if release: Chris@87: macros.append((self.release_macro_name + '_%s' Chris@87: % (release.replace('.', '_')), None)) Chris@87: opts = self.get_config_output(config_exe, '--libs') Chris@87: if opts: Chris@87: for opt in opts.split(): Chris@87: if opt[:2] == '-l': Chris@87: libraries.append(opt[2:]) Chris@87: elif opt[:2] == '-L': Chris@87: library_dirs.append(opt[2:]) Chris@87: else: Chris@87: extra_link_args.append(opt) Chris@87: opts = self.get_config_output(config_exe, self.cflags_flag) Chris@87: if opts: Chris@87: for opt in opts.split(): Chris@87: if opt[:2] == '-I': Chris@87: include_dirs.append(opt[2:]) Chris@87: elif opt[:2] == '-D': Chris@87: if '=' in opt: Chris@87: n, v = opt[2:].split('=') Chris@87: macros.append((n, v)) Chris@87: else: Chris@87: macros.append((opt[2:], None)) Chris@87: else: Chris@87: extra_compile_args.append(opt) Chris@87: if macros: Chris@87: dict_append(info, define_macros=macros) Chris@87: if libraries: Chris@87: dict_append(info, libraries=libraries) Chris@87: if library_dirs: Chris@87: dict_append(info, library_dirs=library_dirs) Chris@87: if include_dirs: Chris@87: dict_append(info, include_dirs=include_dirs) Chris@87: if extra_link_args: Chris@87: dict_append(info, extra_link_args=extra_link_args) Chris@87: if extra_compile_args: Chris@87: dict_append(info, extra_compile_args=extra_compile_args) Chris@87: if info: Chris@87: self.set_info(**info) Chris@87: return Chris@87: Chris@87: Chris@87: class wx_info(_pkg_config_info): Chris@87: section = 'wx' Chris@87: config_env_var = 'WX_CONFIG' Chris@87: default_config_exe = 'wx-config' Chris@87: append_config_exe = '' Chris@87: version_macro_name = 'WX_VERSION' Chris@87: release_macro_name = 'WX_RELEASE' Chris@87: version_flag = '--version' Chris@87: cflags_flag = '--cxxflags' Chris@87: Chris@87: Chris@87: class gdk_pixbuf_xlib_2_info(_pkg_config_info): Chris@87: section = 'gdk_pixbuf_xlib_2' Chris@87: append_config_exe = 'gdk-pixbuf-xlib-2.0' Chris@87: version_macro_name = 'GDK_PIXBUF_XLIB_VERSION' Chris@87: Chris@87: Chris@87: class gdk_pixbuf_2_info(_pkg_config_info): Chris@87: section = 'gdk_pixbuf_2' Chris@87: append_config_exe = 'gdk-pixbuf-2.0' Chris@87: version_macro_name = 'GDK_PIXBUF_VERSION' Chris@87: Chris@87: Chris@87: class gdk_x11_2_info(_pkg_config_info): Chris@87: section = 'gdk_x11_2' Chris@87: append_config_exe = 'gdk-x11-2.0' Chris@87: version_macro_name = 'GDK_X11_VERSION' Chris@87: Chris@87: Chris@87: class gdk_2_info(_pkg_config_info): Chris@87: section = 'gdk_2' Chris@87: append_config_exe = 'gdk-2.0' Chris@87: version_macro_name = 'GDK_VERSION' Chris@87: Chris@87: Chris@87: class gdk_info(_pkg_config_info): Chris@87: section = 'gdk' Chris@87: append_config_exe = 'gdk' Chris@87: version_macro_name = 'GDK_VERSION' Chris@87: Chris@87: Chris@87: class gtkp_x11_2_info(_pkg_config_info): Chris@87: section = 'gtkp_x11_2' Chris@87: append_config_exe = 'gtk+-x11-2.0' Chris@87: version_macro_name = 'GTK_X11_VERSION' Chris@87: Chris@87: Chris@87: class gtkp_2_info(_pkg_config_info): Chris@87: section = 'gtkp_2' Chris@87: append_config_exe = 'gtk+-2.0' Chris@87: version_macro_name = 'GTK_VERSION' Chris@87: Chris@87: Chris@87: class xft_info(_pkg_config_info): Chris@87: section = 'xft' Chris@87: append_config_exe = 'xft' Chris@87: version_macro_name = 'XFT_VERSION' Chris@87: Chris@87: Chris@87: class freetype2_info(_pkg_config_info): Chris@87: section = 'freetype2' Chris@87: append_config_exe = 'freetype2' Chris@87: version_macro_name = 'FREETYPE2_VERSION' Chris@87: Chris@87: Chris@87: class amd_info(system_info): Chris@87: section = 'amd' Chris@87: dir_env_var = 'AMD' Chris@87: _lib_names = ['amd'] Chris@87: Chris@87: def calc_info(self): Chris@87: lib_dirs = self.get_lib_dirs() Chris@87: Chris@87: amd_libs = self.get_libs('amd_libs', self._lib_names) Chris@87: info = self.check_libs(lib_dirs, amd_libs, []) Chris@87: if info is None: Chris@87: return Chris@87: Chris@87: include_dirs = self.get_include_dirs() Chris@87: Chris@87: inc_dir = None Chris@87: for d in include_dirs: Chris@87: p = self.combine_paths(d, 'amd.h') Chris@87: if p: Chris@87: inc_dir = os.path.dirname(p[0]) Chris@87: break Chris@87: if inc_dir is not None: Chris@87: dict_append(info, include_dirs=[inc_dir], Chris@87: define_macros=[('SCIPY_AMD_H', None)], Chris@87: swig_opts=['-I' + inc_dir]) Chris@87: Chris@87: self.set_info(**info) Chris@87: return Chris@87: Chris@87: Chris@87: class umfpack_info(system_info): Chris@87: section = 'umfpack' Chris@87: dir_env_var = 'UMFPACK' Chris@87: notfounderror = UmfpackNotFoundError Chris@87: _lib_names = ['umfpack'] Chris@87: Chris@87: def calc_info(self): Chris@87: lib_dirs = self.get_lib_dirs() Chris@87: Chris@87: umfpack_libs = self.get_libs('umfpack_libs', self._lib_names) Chris@87: info = self.check_libs(lib_dirs, umfpack_libs, []) Chris@87: if info is None: Chris@87: return Chris@87: Chris@87: include_dirs = self.get_include_dirs() Chris@87: Chris@87: inc_dir = None Chris@87: for d in include_dirs: Chris@87: p = self.combine_paths(d, ['', 'umfpack'], 'umfpack.h') Chris@87: if p: Chris@87: inc_dir = os.path.dirname(p[0]) Chris@87: break Chris@87: if inc_dir is not None: Chris@87: dict_append(info, include_dirs=[inc_dir], Chris@87: define_macros=[('SCIPY_UMFPACK_H', None)], Chris@87: swig_opts=['-I' + inc_dir]) Chris@87: Chris@87: amd = get_info('amd') Chris@87: dict_append(info, **get_info('amd')) Chris@87: Chris@87: self.set_info(**info) Chris@87: return Chris@87: Chris@87: ## def vstr2hex(version): Chris@87: ## bits = [] Chris@87: ## n = [24,16,8,4,0] Chris@87: ## r = 0 Chris@87: ## for s in version.split('.'): Chris@87: ## r |= int(s) << n[0] Chris@87: ## del n[0] Chris@87: ## return r Chris@87: Chris@87: #-------------------------------------------------------------------- Chris@87: Chris@87: Chris@87: def combine_paths(*args, **kws): Chris@87: """ Return a list of existing paths composed by all combinations of Chris@87: items from arguments. Chris@87: """ Chris@87: r = [] Chris@87: for a in args: Chris@87: if not a: Chris@87: continue Chris@87: if is_string(a): Chris@87: a = [a] Chris@87: r.append(a) Chris@87: args = r Chris@87: if not args: Chris@87: return [] Chris@87: if len(args) == 1: Chris@87: result = reduce(lambda a, b: a + b, map(glob, args[0]), []) Chris@87: elif len(args) == 2: Chris@87: result = [] Chris@87: for a0 in args[0]: Chris@87: for a1 in args[1]: Chris@87: result.extend(glob(os.path.join(a0, a1))) Chris@87: else: Chris@87: result = combine_paths(*(combine_paths(args[0], args[1]) + args[2:])) Chris@87: verbosity = kws.get('verbosity', 1) Chris@87: log.debug('(paths: %s)', ','.join(result)) Chris@87: return result Chris@87: Chris@87: language_map = {'c': 0, 'c++': 1, 'f77': 2, 'f90': 3} Chris@87: inv_language_map = {0: 'c', 1: 'c++', 2: 'f77', 3: 'f90'} Chris@87: Chris@87: Chris@87: def dict_append(d, **kws): Chris@87: languages = [] Chris@87: for k, v in kws.items(): Chris@87: if k == 'language': Chris@87: languages.append(v) Chris@87: continue Chris@87: if k in d: Chris@87: if k in ['library_dirs', 'include_dirs', 'define_macros']: Chris@87: [d[k].append(vv) for vv in v if vv not in d[k]] Chris@87: else: Chris@87: d[k].extend(v) Chris@87: else: Chris@87: d[k] = v Chris@87: if languages: Chris@87: l = inv_language_map[max([language_map.get(l, 0) for l in languages])] Chris@87: d['language'] = l Chris@87: return Chris@87: Chris@87: Chris@87: def parseCmdLine(argv=(None,)): Chris@87: import optparse Chris@87: parser = optparse.OptionParser("usage: %prog [-v] [info objs]") Chris@87: parser.add_option('-v', '--verbose', action='store_true', dest='verbose', Chris@87: default=False, Chris@87: help='be verbose and print more messages') Chris@87: Chris@87: opts, args = parser.parse_args(args=argv[1:]) Chris@87: return opts, args Chris@87: Chris@87: Chris@87: def show_all(argv=None): Chris@87: import inspect Chris@87: if argv is None: Chris@87: argv = sys.argv Chris@87: opts, args = parseCmdLine(argv) Chris@87: if opts.verbose: Chris@87: log.set_threshold(log.DEBUG) Chris@87: else: Chris@87: log.set_threshold(log.INFO) Chris@87: show_only = [] Chris@87: for n in args: Chris@87: if n[-5:] != '_info': Chris@87: n = n + '_info' Chris@87: show_only.append(n) Chris@87: show_all = not show_only Chris@87: _gdict_ = globals().copy() Chris@87: for name, c in _gdict_.items(): Chris@87: if not inspect.isclass(c): Chris@87: continue Chris@87: if not issubclass(c, system_info) or c is system_info: Chris@87: continue Chris@87: if not show_all: Chris@87: if name not in show_only: Chris@87: continue Chris@87: del show_only[show_only.index(name)] Chris@87: conf = c() Chris@87: conf.verbosity = 2 Chris@87: r = conf.get_info() Chris@87: if show_only: Chris@87: log.info('Info classes not defined: %s', ','.join(show_only)) Chris@87: Chris@87: if __name__ == "__main__": Chris@87: show_all()