| #!/usr/bin/env python3 |
| """ |
| This file defines a set of system_info classes for getting |
| information about various resources (libraries, library directories, |
| include directories, etc.) in the system. Usage: |
| info_dict = get_info(<name>) |
| where <name> is a string 'atlas','x11','fftw','lapack','blas', |
| 'lapack_src', 'blas_src', etc. For a complete list of allowed names, |
| see the definition of get_info() function below. |
| |
| Returned info_dict is a dictionary which is compatible with |
| distutils.setup keyword arguments. If info_dict == {}, then the |
| asked resource is not available (system_info could not find it). |
| |
| Several *_info classes specify an environment variable to specify |
| the locations of software. When setting the corresponding environment |
| variable to 'None' then the software will be ignored, even when it |
| is available in system. |
| |
| Global parameters: |
| system_info.search_static_first - search static libraries (.a) |
| in precedence to shared ones (.so, .sl) if enabled. |
| system_info.verbosity - output the results to stdout if enabled. |
| |
| The file 'site.cfg' is looked for in |
| |
| 1) Directory of main setup.py file being run. |
| 2) Home directory of user running the setup.py file as ~/.numpy-site.cfg |
| 3) System wide directory (location of this file...) |
| |
| The first one found is used to get system configuration options The |
| format is that used by ConfigParser (i.e., Windows .INI style). The |
| section ALL is not intended for general use. |
| |
| Appropriate defaults are used if nothing is specified. |
| |
| The order of finding the locations of resources is the following: |
| 1. environment variable |
| 2. section in site.cfg |
| 3. DEFAULT section in site.cfg |
| 4. System default search paths (see ``default_*`` variables below). |
| Only the first complete match is returned. |
| |
| Currently, the following classes are available, along with their section names: |
| |
| Numeric_info:Numeric |
| _numpy_info:Numeric |
| _pkg_config_info:None |
| accelerate_info:accelerate |
| agg2_info:agg2 |
| amd_info:amd |
| atlas_3_10_blas_info:atlas |
| atlas_3_10_blas_threads_info:atlas |
| atlas_3_10_info:atlas |
| atlas_3_10_threads_info:atlas |
| atlas_blas_info:atlas |
| atlas_blas_threads_info:atlas |
| atlas_info:atlas |
| atlas_threads_info:atlas |
| blas64__opt_info:ALL # usage recommended (general ILP64 BLAS, 64_ symbol suffix) |
| blas_ilp64_opt_info:ALL # usage recommended (general ILP64 BLAS) |
| blas_ilp64_plain_opt_info:ALL # usage recommended (general ILP64 BLAS, no symbol suffix) |
| blas_info:blas |
| blas_mkl_info:mkl |
| blas_ssl2_info:ssl2 |
| blas_opt_info:ALL # usage recommended |
| blas_src_info:blas_src |
| blis_info:blis |
| boost_python_info:boost_python |
| dfftw_info:fftw |
| dfftw_threads_info:fftw |
| djbfft_info:djbfft |
| f2py_info:ALL |
| fft_opt_info:ALL |
| fftw2_info:fftw |
| fftw3_info:fftw3 |
| fftw_info:fftw |
| fftw_threads_info:fftw |
| flame_info:flame |
| freetype2_info:freetype2 |
| gdk_2_info:gdk_2 |
| gdk_info:gdk |
| gdk_pixbuf_2_info:gdk_pixbuf_2 |
| gdk_pixbuf_xlib_2_info:gdk_pixbuf_xlib_2 |
| gdk_x11_2_info:gdk_x11_2 |
| gtkp_2_info:gtkp_2 |
| gtkp_x11_2_info:gtkp_x11_2 |
| lapack64__opt_info:ALL # usage recommended (general ILP64 LAPACK, 64_ symbol suffix) |
| lapack_atlas_3_10_info:atlas |
| lapack_atlas_3_10_threads_info:atlas |
| lapack_atlas_info:atlas |
| lapack_atlas_threads_info:atlas |
| lapack_ilp64_opt_info:ALL # usage recommended (general ILP64 LAPACK) |
| lapack_ilp64_plain_opt_info:ALL # usage recommended (general ILP64 LAPACK, no symbol suffix) |
| lapack_info:lapack |
| lapack_mkl_info:mkl |
| lapack_ssl2_info:ssl2 |
| lapack_opt_info:ALL # usage recommended |
| lapack_src_info:lapack_src |
| mkl_info:mkl |
| ssl2_info:ssl2 |
| numarray_info:numarray |
| numerix_info:numerix |
| numpy_info:numpy |
| openblas64__info:openblas64_ |
| openblas64__lapack_info:openblas64_ |
| openblas_clapack_info:openblas |
| openblas_ilp64_info:openblas_ilp64 |
| openblas_ilp64_lapack_info:openblas_ilp64 |
| openblas_info:openblas |
| openblas_lapack_info:openblas |
| sfftw_info:fftw |
| sfftw_threads_info:fftw |
| system_info:ALL |
| umfpack_info:umfpack |
| wx_info:wx |
| x11_info:x11 |
| xft_info:xft |
| |
| Note that blas_opt_info and lapack_opt_info honor the NPY_BLAS_ORDER |
| and NPY_LAPACK_ORDER environment variables to determine the order in which |
| specific BLAS and LAPACK libraries are searched for. |
| |
| This search (or autodetection) can be bypassed by defining the environment |
| variables NPY_BLAS_LIBS and NPY_LAPACK_LIBS, which should then contain the |
| exact linker flags to use (language will be set to F77). Building against |
| Netlib BLAS/LAPACK or stub files, in order to be able to switch BLAS and LAPACK |
| implementations at runtime. If using this to build NumPy itself, it is |
| recommended to also define NPY_CBLAS_LIBS (assuming your BLAS library has a |
| CBLAS interface) to enable CBLAS usage for matrix multiplication (unoptimized |
| otherwise). |
| |
| Example: |
| ---------- |
| [DEFAULT] |
| # default section |
| library_dirs = /usr/lib:/usr/local/lib:/opt/lib |
| include_dirs = /usr/include:/usr/local/include:/opt/include |
| src_dirs = /usr/local/src:/opt/src |
| # search static libraries (.a) in preference to shared ones (.so) |
| search_static_first = 0 |
| |
| [fftw] |
| libraries = rfftw, fftw |
| |
| [atlas] |
| library_dirs = /usr/lib/3dnow:/usr/lib/3dnow/atlas |
| # for overriding the names of the atlas libraries |
| libraries = lapack, f77blas, cblas, atlas |
| |
| [x11] |
| library_dirs = /usr/X11R6/lib |
| include_dirs = /usr/X11R6/include |
| ---------- |
| |
| Note that the ``libraries`` key is the default setting for libraries. |
| |
| Authors: |
| Pearu Peterson <pearu@cens.ioc.ee>, February 2002 |
| David M. Cooke <cookedm@physics.mcmaster.ca>, April 2002 |
| |
| Copyright 2002 Pearu Peterson all rights reserved, |
| Pearu Peterson <pearu@cens.ioc.ee> |
| Permission to use, modify, and distribute this software is given under the |
| terms of the NumPy (BSD style) license. See LICENSE.txt that came with |
| this distribution for specifics. |
| |
| NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. |
| |
| """ |
| import sys |
| import os |
| import re |
| import copy |
| import warnings |
| import subprocess |
| import textwrap |
| |
| from glob import glob |
| from functools import reduce |
| from configparser import NoOptionError |
| from configparser import RawConfigParser as ConfigParser |
| # It seems that some people are importing ConfigParser from here so is |
| # good to keep its class name. Use of RawConfigParser is needed in |
| # order to be able to load path names with percent in them, like |
| # `feature%2Fcool` which is common on git flow branch names. |
| |
| from distutils.errors import DistutilsError |
| from distutils.dist import Distribution |
| import sysconfig |
| from numpy.distutils import log |
| from distutils.util import get_platform |
| |
| from numpy.distutils.exec_command import ( |
| find_executable, filepath_from_subprocess_output, |
| ) |
| from numpy.distutils.misc_util import (is_sequence, is_string, |
| get_shared_lib_extension) |
| from numpy.distutils.command.config import config as cmd_config |
| from numpy.distutils import customized_ccompiler as _customized_ccompiler |
| from numpy.distutils import _shell_utils |
| import distutils.ccompiler |
| import tempfile |
| import shutil |
| |
| __all__ = ['system_info'] |
| |
| # Determine number of bits |
| import platform |
| _bits = {'32bit': 32, '64bit': 64} |
| platform_bits = _bits[platform.architecture()[0]] |
| |
| |
| global_compiler = None |
| |
| def customized_ccompiler(): |
| global global_compiler |
| if not global_compiler: |
| global_compiler = _customized_ccompiler() |
| return global_compiler |
| |
| |
| def _c_string_literal(s): |
| """ |
| Convert a python string into a literal suitable for inclusion into C code |
| """ |
| # only these three characters are forbidden in C strings |
| s = s.replace('\\', r'\\') |
| s = s.replace('"', r'\"') |
| s = s.replace('\n', r'\n') |
| return '"{}"'.format(s) |
| |
| |
| def libpaths(paths, bits): |
| """Return a list of library paths valid on 32 or 64 bit systems. |
| |
| Inputs: |
| paths : sequence |
| A sequence of strings (typically paths) |
| bits : int |
| An integer, the only valid values are 32 or 64. A ValueError exception |
| is raised otherwise. |
| |
| Examples: |
| |
| Consider a list of directories |
| >>> paths = ['/usr/X11R6/lib','/usr/X11/lib','/usr/lib'] |
| |
| For a 32-bit platform, this is already valid: |
| >>> np.distutils.system_info.libpaths(paths,32) |
| ['/usr/X11R6/lib', '/usr/X11/lib', '/usr/lib'] |
| |
| On 64 bits, we prepend the '64' postfix |
| >>> np.distutils.system_info.libpaths(paths,64) |
| ['/usr/X11R6/lib64', '/usr/X11R6/lib', '/usr/X11/lib64', '/usr/X11/lib', |
| '/usr/lib64', '/usr/lib'] |
| """ |
| if bits not in (32, 64): |
| raise ValueError("Invalid bit size in libpaths: 32 or 64 only") |
| |
| # Handle 32bit case |
| if bits == 32: |
| return paths |
| |
| # Handle 64bit case |
| out = [] |
| for p in paths: |
| out.extend([p + '64', p]) |
| |
| return out |
| |
| |
| if sys.platform == 'win32': |
| default_lib_dirs = ['C:\\', |
| os.path.join(sysconfig.get_config_var('exec_prefix'), |
| 'libs')] |
| default_runtime_dirs = [] |
| default_include_dirs = [] |
| default_src_dirs = ['.'] |
| default_x11_lib_dirs = [] |
| default_x11_include_dirs = [] |
| _include_dirs = [ |
| 'include', |
| 'include/suitesparse', |
| ] |
| _lib_dirs = [ |
| 'lib', |
| ] |
| |
| _include_dirs = [d.replace('/', os.sep) for d in _include_dirs] |
| _lib_dirs = [d.replace('/', os.sep) for d in _lib_dirs] |
| def add_system_root(library_root): |
| """Add a package manager root to the include directories""" |
| global default_lib_dirs |
| global default_include_dirs |
| |
| library_root = os.path.normpath(library_root) |
| |
| default_lib_dirs.extend( |
| os.path.join(library_root, d) for d in _lib_dirs) |
| default_include_dirs.extend( |
| os.path.join(library_root, d) for d in _include_dirs) |
| |
| # VCpkg is the de-facto package manager on windows for C/C++ |
| # libraries. If it is on the PATH, then we append its paths here. |
| vcpkg = shutil.which('vcpkg') |
| if vcpkg: |
| vcpkg_dir = os.path.dirname(vcpkg) |
| if platform.architecture()[0] == '32bit': |
| specifier = 'x86' |
| else: |
| specifier = 'x64' |
| |
| vcpkg_installed = os.path.join(vcpkg_dir, 'installed') |
| for vcpkg_root in [ |
| os.path.join(vcpkg_installed, specifier + '-windows'), |
| os.path.join(vcpkg_installed, specifier + '-windows-static'), |
| ]: |
| add_system_root(vcpkg_root) |
| |
| # Conda is another popular package manager that provides libraries |
| conda = shutil.which('conda') |
| if conda: |
| conda_dir = os.path.dirname(conda) |
| add_system_root(os.path.join(conda_dir, '..', 'Library')) |
| add_system_root(os.path.join(conda_dir, 'Library')) |
| |
| else: |
| default_lib_dirs = libpaths(['/usr/local/lib', '/opt/lib', '/usr/lib', |
| '/opt/local/lib', '/sw/lib'], platform_bits) |
| default_runtime_dirs = [] |
| default_include_dirs = ['/usr/local/include', |
| '/opt/include', |
| # path of umfpack under macports |
| '/opt/local/include/ufsparse', |
| '/opt/local/include', '/sw/include', |
| '/usr/include/suitesparse'] |
| default_src_dirs = ['.', '/usr/local/src', '/opt/src', '/sw/src'] |
| |
| default_x11_lib_dirs = libpaths(['/usr/X11R6/lib', '/usr/X11/lib', |
| '/usr/lib'], platform_bits) |
| default_x11_include_dirs = ['/usr/X11R6/include', '/usr/X11/include'] |
| |
| if os.path.exists('/usr/lib/X11'): |
| globbed_x11_dir = glob('/usr/lib/*/libX11.so') |
| if globbed_x11_dir: |
| x11_so_dir = os.path.split(globbed_x11_dir[0])[0] |
| default_x11_lib_dirs.extend([x11_so_dir, '/usr/lib/X11']) |
| default_x11_include_dirs.extend(['/usr/lib/X11/include', |
| '/usr/include/X11']) |
| |
| with open(os.devnull, 'w') as tmp: |
| try: |
| p = subprocess.Popen(["gcc", "-print-multiarch"], stdout=subprocess.PIPE, |
| stderr=tmp) |
| except (OSError, DistutilsError): |
| # OSError if gcc is not installed, or SandboxViolation (DistutilsError |
| # subclass) if an old setuptools bug is triggered (see gh-3160). |
| pass |
| else: |
| triplet = str(p.communicate()[0].decode().strip()) |
| if p.returncode == 0: |
| # gcc supports the "-print-multiarch" option |
| default_x11_lib_dirs += [os.path.join("/usr/lib/", triplet)] |
| default_lib_dirs += [os.path.join("/usr/lib/", triplet)] |
| |
| |
| if os.path.join(sys.prefix, 'lib') not in default_lib_dirs: |
| default_lib_dirs.insert(0, os.path.join(sys.prefix, 'lib')) |
| default_include_dirs.append(os.path.join(sys.prefix, 'include')) |
| default_src_dirs.append(os.path.join(sys.prefix, 'src')) |
| |
| default_lib_dirs = [_m for _m in default_lib_dirs if os.path.isdir(_m)] |
| default_runtime_dirs = [_m for _m in default_runtime_dirs if os.path.isdir(_m)] |
| default_include_dirs = [_m for _m in default_include_dirs if os.path.isdir(_m)] |
| default_src_dirs = [_m for _m in default_src_dirs if os.path.isdir(_m)] |
| |
| so_ext = get_shared_lib_extension() |
| |
| |
| def get_standard_file(fname): |
| """Returns a list of files named 'fname' from |
| 1) System-wide directory (directory-location of this module) |
| 2) Users HOME directory (os.environ['HOME']) |
| 3) Local directory |
| """ |
| # System-wide file |
| filenames = [] |
| try: |
| f = __file__ |
| except NameError: |
| f = sys.argv[0] |
| sysfile = os.path.join(os.path.split(os.path.abspath(f))[0], |
| fname) |
| if os.path.isfile(sysfile): |
| filenames.append(sysfile) |
| |
| # Home directory |
| # And look for the user config file |
| try: |
| f = os.path.expanduser('~') |
| except KeyError: |
| pass |
| else: |
| user_file = os.path.join(f, fname) |
| if os.path.isfile(user_file): |
| filenames.append(user_file) |
| |
| # Local file |
| if os.path.isfile(fname): |
| filenames.append(os.path.abspath(fname)) |
| |
| return filenames |
| |
| |
| def _parse_env_order(base_order, env): |
| """ Parse an environment variable `env` by splitting with "," and only returning elements from `base_order` |
| |
| This method will sequence the environment variable and check for their |
| individual elements in `base_order`. |
| |
| The items in the environment variable may be negated via '^item' or '!itema,itemb'. |
| It must start with ^/! to negate all options. |
| |
| Raises |
| ------ |
| ValueError: for mixed negated and non-negated orders or multiple negated orders |
| |
| Parameters |
| ---------- |
| base_order : list of str |
| the base list of orders |
| env : str |
| the environment variable to be parsed, if none is found, `base_order` is returned |
| |
| Returns |
| ------- |
| allow_order : list of str |
| allowed orders in lower-case |
| unknown_order : list of str |
| for values not overlapping with `base_order` |
| """ |
| order_str = os.environ.get(env, None) |
| |
| # ensure all base-orders are lower-case (for easier comparison) |
| base_order = [order.lower() for order in base_order] |
| if order_str is None: |
| return base_order, [] |
| |
| neg = order_str.startswith('^') or order_str.startswith('!') |
| # Check format |
| order_str_l = list(order_str) |
| sum_neg = order_str_l.count('^') + order_str_l.count('!') |
| if neg: |
| if sum_neg > 1: |
| raise ValueError(f"Environment variable '{env}' may only contain a single (prefixed) negation: {order_str}") |
| # remove prefix |
| order_str = order_str[1:] |
| elif sum_neg > 0: |
| raise ValueError(f"Environment variable '{env}' may not mix negated an non-negated items: {order_str}") |
| |
| # Split and lower case |
| orders = order_str.lower().split(',') |
| |
| # to inform callee about non-overlapping elements |
| unknown_order = [] |
| |
| # if negated, we have to remove from the order |
| if neg: |
| allow_order = base_order.copy() |
| |
| for order in orders: |
| if not order: |
| continue |
| |
| if order not in base_order: |
| unknown_order.append(order) |
| continue |
| |
| if order in allow_order: |
| allow_order.remove(order) |
| |
| else: |
| allow_order = [] |
| |
| for order in orders: |
| if not order: |
| continue |
| |
| if order not in base_order: |
| unknown_order.append(order) |
| continue |
| |
| if order not in allow_order: |
| allow_order.append(order) |
| |
| return allow_order, unknown_order |
| |
| |
| def get_info(name, notfound_action=0): |
| """ |
| notfound_action: |
| 0 - do nothing |
| 1 - display warning message |
| 2 - raise error |
| """ |
| cl = {'armpl': armpl_info, |
| 'blas_armpl': blas_armpl_info, |
| 'lapack_armpl': lapack_armpl_info, |
| 'fftw3_armpl': fftw3_armpl_info, |
| 'atlas': atlas_info, # use lapack_opt or blas_opt instead |
| 'atlas_threads': atlas_threads_info, # ditto |
| 'atlas_blas': atlas_blas_info, |
| 'atlas_blas_threads': atlas_blas_threads_info, |
| 'lapack_atlas': lapack_atlas_info, # use lapack_opt instead |
| 'lapack_atlas_threads': lapack_atlas_threads_info, # ditto |
| 'atlas_3_10': atlas_3_10_info, # use lapack_opt or blas_opt instead |
| 'atlas_3_10_threads': atlas_3_10_threads_info, # ditto |
| 'atlas_3_10_blas': atlas_3_10_blas_info, |
| 'atlas_3_10_blas_threads': atlas_3_10_blas_threads_info, |
| 'lapack_atlas_3_10': lapack_atlas_3_10_info, # use lapack_opt instead |
| 'lapack_atlas_3_10_threads': lapack_atlas_3_10_threads_info, # ditto |
| 'flame': flame_info, # use lapack_opt instead |
| 'mkl': mkl_info, |
| 'ssl2': ssl2_info, |
| # openblas which may or may not have embedded lapack |
| 'openblas': openblas_info, # use blas_opt instead |
| # openblas with embedded lapack |
| 'openblas_lapack': openblas_lapack_info, # use blas_opt instead |
| 'openblas_clapack': openblas_clapack_info, # use blas_opt instead |
| 'blis': blis_info, # use blas_opt instead |
| 'lapack_mkl': lapack_mkl_info, # use lapack_opt instead |
| 'blas_mkl': blas_mkl_info, # use blas_opt instead |
| 'lapack_ssl2': lapack_ssl2_info, |
| 'blas_ssl2': blas_ssl2_info, |
| 'accelerate': accelerate_info, # use blas_opt instead |
| 'openblas64_': openblas64__info, |
| 'openblas64__lapack': openblas64__lapack_info, |
| 'openblas_ilp64': openblas_ilp64_info, |
| 'openblas_ilp64_lapack': openblas_ilp64_lapack_info, |
| 'x11': x11_info, |
| 'fft_opt': fft_opt_info, |
| 'fftw': fftw_info, |
| 'fftw2': fftw2_info, |
| 'fftw3': fftw3_info, |
| 'dfftw': dfftw_info, |
| 'sfftw': sfftw_info, |
| 'fftw_threads': fftw_threads_info, |
| 'dfftw_threads': dfftw_threads_info, |
| 'sfftw_threads': sfftw_threads_info, |
| 'djbfft': djbfft_info, |
| 'blas': blas_info, # use blas_opt instead |
| 'lapack': lapack_info, # use lapack_opt instead |
| 'lapack_src': lapack_src_info, |
| 'blas_src': blas_src_info, |
| 'numpy': numpy_info, |
| 'f2py': f2py_info, |
| 'Numeric': Numeric_info, |
| 'numeric': Numeric_info, |
| 'numarray': numarray_info, |
| 'numerix': numerix_info, |
| 'lapack_opt': lapack_opt_info, |
| 'lapack_ilp64_opt': lapack_ilp64_opt_info, |
| 'lapack_ilp64_plain_opt': lapack_ilp64_plain_opt_info, |
| 'lapack64__opt': lapack64__opt_info, |
| 'blas_opt': blas_opt_info, |
| 'blas_ilp64_opt': blas_ilp64_opt_info, |
| 'blas_ilp64_plain_opt': blas_ilp64_plain_opt_info, |
| 'blas64__opt': blas64__opt_info, |
| 'boost_python': boost_python_info, |
| 'agg2': agg2_info, |
| 'wx': wx_info, |
| 'gdk_pixbuf_xlib_2': gdk_pixbuf_xlib_2_info, |
| 'gdk-pixbuf-xlib-2.0': gdk_pixbuf_xlib_2_info, |
| 'gdk_pixbuf_2': gdk_pixbuf_2_info, |
| 'gdk-pixbuf-2.0': gdk_pixbuf_2_info, |
| 'gdk': gdk_info, |
| 'gdk_2': gdk_2_info, |
| 'gdk-2.0': gdk_2_info, |
| 'gdk_x11_2': gdk_x11_2_info, |
| 'gdk-x11-2.0': gdk_x11_2_info, |
| 'gtkp_x11_2': gtkp_x11_2_info, |
| 'gtk+-x11-2.0': gtkp_x11_2_info, |
| 'gtkp_2': gtkp_2_info, |
| 'gtk+-2.0': gtkp_2_info, |
| 'xft': xft_info, |
| 'freetype2': freetype2_info, |
| 'umfpack': umfpack_info, |
| 'amd': amd_info, |
| }.get(name.lower(), system_info) |
| return cl().get_info(notfound_action) |
| |
| |
| class NotFoundError(DistutilsError): |
| """Some third-party program or library is not found.""" |
| |
| |
| class AliasedOptionError(DistutilsError): |
| """ |
| Aliases entries in config files should not be existing. |
| In section '{section}' we found multiple appearances of options {options}.""" |
| |
| |
| class AtlasNotFoundError(NotFoundError): |
| """ |
| Atlas (http://github.com/math-atlas/math-atlas) libraries not found. |
| Directories to search for the libraries can be specified in the |
| numpy/distutils/site.cfg file (section [atlas]) or by setting |
| the ATLAS environment variable.""" |
| |
| |
| class FlameNotFoundError(NotFoundError): |
| """ |
| FLAME (http://www.cs.utexas.edu/~flame/web/) libraries not found. |
| Directories to search for the libraries can be specified in the |
| numpy/distutils/site.cfg file (section [flame]).""" |
| |
| |
| class LapackNotFoundError(NotFoundError): |
| """ |
| Lapack (http://www.netlib.org/lapack/) libraries not found. |
| Directories to search for the libraries can be specified in the |
| numpy/distutils/site.cfg file (section [lapack]) or by setting |
| the LAPACK environment variable.""" |
| |
| |
| class LapackSrcNotFoundError(LapackNotFoundError): |
| """ |
| Lapack (http://www.netlib.org/lapack/) sources not found. |
| Directories to search for the sources can be specified in the |
| numpy/distutils/site.cfg file (section [lapack_src]) or by setting |
| the LAPACK_SRC environment variable.""" |
| |
| |
| class LapackILP64NotFoundError(NotFoundError): |
| """ |
| 64-bit Lapack libraries not found. |
| Known libraries in numpy/distutils/site.cfg file are: |
| openblas64_, openblas_ilp64 |
| """ |
| |
| class BlasOptNotFoundError(NotFoundError): |
| """ |
| Optimized (vendor) Blas libraries are not found. |
| Falls back to netlib Blas library which has worse performance. |
| A better performance should be easily gained by switching |
| Blas library.""" |
| |
| class BlasNotFoundError(NotFoundError): |
| """ |
| Blas (http://www.netlib.org/blas/) libraries not found. |
| Directories to search for the libraries can be specified in the |
| numpy/distutils/site.cfg file (section [blas]) or by setting |
| the BLAS environment variable.""" |
| |
| class BlasILP64NotFoundError(NotFoundError): |
| """ |
| 64-bit Blas libraries not found. |
| Known libraries in numpy/distutils/site.cfg file are: |
| openblas64_, openblas_ilp64 |
| """ |
| |
| class BlasSrcNotFoundError(BlasNotFoundError): |
| """ |
| Blas (http://www.netlib.org/blas/) sources not found. |
| Directories to search for the sources can be specified in the |
| numpy/distutils/site.cfg file (section [blas_src]) or by setting |
| the BLAS_SRC environment variable.""" |
| |
| |
| class FFTWNotFoundError(NotFoundError): |
| """ |
| FFTW (http://www.fftw.org/) libraries not found. |
| Directories to search for the libraries can be specified in the |
| numpy/distutils/site.cfg file (section [fftw]) or by setting |
| the FFTW environment variable.""" |
| |
| |
| class DJBFFTNotFoundError(NotFoundError): |
| """ |
| DJBFFT (https://cr.yp.to/djbfft.html) libraries not found. |
| Directories to search for the libraries can be specified in the |
| numpy/distutils/site.cfg file (section [djbfft]) or by setting |
| the DJBFFT environment variable.""" |
| |
| |
| class NumericNotFoundError(NotFoundError): |
| """ |
| Numeric (https://www.numpy.org/) module not found. |
| Get it from above location, install it, and retry setup.py.""" |
| |
| |
| class X11NotFoundError(NotFoundError): |
| """X11 libraries not found.""" |
| |
| |
| class UmfpackNotFoundError(NotFoundError): |
| """ |
| UMFPACK sparse solver (https://www.cise.ufl.edu/research/sparse/umfpack/) |
| not found. Directories to search for the libraries can be specified in the |
| numpy/distutils/site.cfg file (section [umfpack]) or by setting |
| the UMFPACK environment variable.""" |
| |
| |
| class system_info: |
| |
| """ get_info() is the only public method. Don't use others. |
| """ |
| dir_env_var = None |
| # XXX: search_static_first is disabled by default, may disappear in |
| # future unless it is proved to be useful. |
| search_static_first = 0 |
| # The base-class section name is a random word "ALL" and is not really |
| # intended for general use. It cannot be None nor can it be DEFAULT as |
| # these break the ConfigParser. See gh-15338 |
| section = 'ALL' |
| saved_results = {} |
| |
| notfounderror = NotFoundError |
| |
| def __init__(self, |
| default_lib_dirs=default_lib_dirs, |
| default_include_dirs=default_include_dirs, |
| ): |
| self.__class__.info = {} |
| self.local_prefixes = [] |
| defaults = {'library_dirs': os.pathsep.join(default_lib_dirs), |
| 'include_dirs': os.pathsep.join(default_include_dirs), |
| 'runtime_library_dirs': os.pathsep.join(default_runtime_dirs), |
| 'rpath': '', |
| 'src_dirs': os.pathsep.join(default_src_dirs), |
| 'search_static_first': str(self.search_static_first), |
| 'extra_compile_args': '', 'extra_link_args': ''} |
| self.cp = ConfigParser(defaults) |
| self.files = [] |
| self.files.extend(get_standard_file('.numpy-site.cfg')) |
| self.files.extend(get_standard_file('site.cfg')) |
| self.parse_config_files() |
| |
| if self.section is not None: |
| self.search_static_first = self.cp.getboolean( |
| self.section, 'search_static_first') |
| assert isinstance(self.search_static_first, int) |
| |
| def parse_config_files(self): |
| self.cp.read(self.files) |
| if not self.cp.has_section(self.section): |
| if self.section is not None: |
| self.cp.add_section(self.section) |
| |
| def calc_libraries_info(self): |
| libs = self.get_libraries() |
| dirs = self.get_lib_dirs() |
| # The extensions use runtime_library_dirs |
| r_dirs = self.get_runtime_lib_dirs() |
| # Intrinsic distutils use rpath, we simply append both entries |
| # as though they were one entry |
| r_dirs.extend(self.get_runtime_lib_dirs(key='rpath')) |
| info = {} |
| for lib in libs: |
| i = self.check_libs(dirs, [lib]) |
| if i is not None: |
| dict_append(info, **i) |
| else: |
| log.info('Library %s was not found. Ignoring' % (lib)) |
| |
| if r_dirs: |
| i = self.check_libs(r_dirs, [lib]) |
| if i is not None: |
| # Swap library keywords found to runtime_library_dirs |
| # the libraries are insisting on the user having defined |
| # them using the library_dirs, and not necessarily by |
| # runtime_library_dirs |
| del i['libraries'] |
| i['runtime_library_dirs'] = i.pop('library_dirs') |
| dict_append(info, **i) |
| else: |
| log.info('Runtime library %s was not found. Ignoring' % (lib)) |
| |
| return info |
| |
| def set_info(self, **info): |
| if info: |
| lib_info = self.calc_libraries_info() |
| dict_append(info, **lib_info) |
| # Update extra information |
| extra_info = self.calc_extra_info() |
| dict_append(info, **extra_info) |
| self.saved_results[self.__class__.__name__] = info |
| |
| def get_option_single(self, *options): |
| """ Ensure that only one of `options` are found in the section |
| |
| Parameters |
| ---------- |
| *options : list of str |
| a list of options to be found in the section (``self.section``) |
| |
| Returns |
| ------- |
| str : |
| the option that is uniquely found in the section |
| |
| Raises |
| ------ |
| AliasedOptionError : |
| in case more than one of the options are found |
| """ |
| found = [self.cp.has_option(self.section, opt) for opt in options] |
| if sum(found) == 1: |
| return options[found.index(True)] |
| elif sum(found) == 0: |
| # nothing is found anyways |
| return options[0] |
| |
| # Else we have more than 1 key found |
| if AliasedOptionError.__doc__ is None: |
| raise AliasedOptionError() |
| raise AliasedOptionError(AliasedOptionError.__doc__.format( |
| section=self.section, options='[{}]'.format(', '.join(options)))) |
| |
| |
| def has_info(self): |
| return self.__class__.__name__ in self.saved_results |
| |
| def calc_extra_info(self): |
| """ Updates the information in the current information with |
| respect to these flags: |
| extra_compile_args |
| extra_link_args |
| """ |
| info = {} |
| for key in ['extra_compile_args', 'extra_link_args']: |
| # Get values |
| opt = self.cp.get(self.section, key) |
| opt = _shell_utils.NativeParser.split(opt) |
| if opt: |
| tmp = {key: opt} |
| dict_append(info, **tmp) |
| return info |
| |
| def get_info(self, notfound_action=0): |
| """ Return a dictionary with items that are compatible |
| with numpy.distutils.setup keyword arguments. |
| """ |
| flag = 0 |
| if not self.has_info(): |
| flag = 1 |
| log.info(self.__class__.__name__ + ':') |
| if hasattr(self, 'calc_info'): |
| self.calc_info() |
| if notfound_action: |
| if not self.has_info(): |
| if notfound_action == 1: |
| warnings.warn(self.notfounderror.__doc__, stacklevel=2) |
| elif notfound_action == 2: |
| raise self.notfounderror(self.notfounderror.__doc__) |
| else: |
| raise ValueError(repr(notfound_action)) |
| |
| if not self.has_info(): |
| log.info(' NOT AVAILABLE') |
| self.set_info() |
| else: |
| log.info(' FOUND:') |
| |
| res = self.saved_results.get(self.__class__.__name__) |
| if log.get_threshold() <= log.INFO and flag: |
| for k, v in res.items(): |
| v = str(v) |
| if k in ['sources', 'libraries'] and len(v) > 270: |
| v = v[:120] + '...\n...\n...' + v[-120:] |
| log.info(' %s = %s', k, v) |
| log.info('') |
| |
| return copy.deepcopy(res) |
| |
| def get_paths(self, section, key): |
| dirs = self.cp.get(section, key).split(os.pathsep) |
| env_var = self.dir_env_var |
| if env_var: |
| if is_sequence(env_var): |
| e0 = env_var[-1] |
| for e in env_var: |
| if e in os.environ: |
| e0 = e |
| break |
| if not env_var[0] == e0: |
| log.info('Setting %s=%s' % (env_var[0], e0)) |
| env_var = e0 |
| if env_var and env_var in os.environ: |
| d = os.environ[env_var] |
| if d == 'None': |
| log.info('Disabled %s: %s', |
| self.__class__.__name__, '(%s is None)' |
| % (env_var,)) |
| return [] |
| if os.path.isfile(d): |
| dirs = [os.path.dirname(d)] + dirs |
| l = getattr(self, '_lib_names', []) |
| if len(l) == 1: |
| b = os.path.basename(d) |
| b = os.path.splitext(b)[0] |
| if b[:3] == 'lib': |
| log.info('Replacing _lib_names[0]==%r with %r' \ |
| % (self._lib_names[0], b[3:])) |
| self._lib_names[0] = b[3:] |
| else: |
| ds = d.split(os.pathsep) |
| ds2 = [] |
| for d in ds: |
| if os.path.isdir(d): |
| ds2.append(d) |
| for dd in ['include', 'lib']: |
| d1 = os.path.join(d, dd) |
| if os.path.isdir(d1): |
| ds2.append(d1) |
| dirs = ds2 + dirs |
| default_dirs = self.cp.get(self.section, key).split(os.pathsep) |
| dirs.extend(default_dirs) |
| ret = [] |
| for d in dirs: |
| if len(d) > 0 and not os.path.isdir(d): |
| warnings.warn('Specified path %s is invalid.' % d, stacklevel=2) |
| continue |
| |
| if d not in ret: |
| ret.append(d) |
| |
| log.debug('( %s = %s )', key, ':'.join(ret)) |
| return ret |
| |
| def get_lib_dirs(self, key='library_dirs'): |
| return self.get_paths(self.section, key) |
| |
| def get_runtime_lib_dirs(self, key='runtime_library_dirs'): |
| path = self.get_paths(self.section, key) |
| if path == ['']: |
| path = [] |
| return path |
| |
| def get_include_dirs(self, key='include_dirs'): |
| return self.get_paths(self.section, key) |
| |
| def get_src_dirs(self, key='src_dirs'): |
| return self.get_paths(self.section, key) |
| |
| def get_libs(self, key, default): |
| try: |
| libs = self.cp.get(self.section, key) |
| except NoOptionError: |
| if not default: |
| return [] |
| if is_string(default): |
| return [default] |
| return default |
| return [b for b in [a.strip() for a in libs.split(',')] if b] |
| |
| def get_libraries(self, key='libraries'): |
| if hasattr(self, '_lib_names'): |
| return self.get_libs(key, default=self._lib_names) |
| else: |
| return self.get_libs(key, '') |
| |
| def library_extensions(self): |
| c = customized_ccompiler() |
| static_exts = [] |
| if c.compiler_type != 'msvc': |
| # MSVC doesn't understand binutils |
| static_exts.append('.a') |
| if sys.platform == 'win32': |
| static_exts.append('.lib') # .lib is used by MSVC and others |
| if self.search_static_first: |
| exts = static_exts + [so_ext] |
| else: |
| exts = [so_ext] + static_exts |
| if sys.platform == 'cygwin': |
| exts.append('.dll.a') |
| if sys.platform == 'darwin': |
| exts.append('.dylib') |
| return exts |
| |
| def check_libs(self, lib_dirs, libs, opt_libs=[]): |
| """If static or shared libraries are available then return |
| their info dictionary. |
| |
| Checks for all libraries as shared libraries first, then |
| static (or vice versa if self.search_static_first is True). |
| """ |
| exts = self.library_extensions() |
| info = None |
| for ext in exts: |
| info = self._check_libs(lib_dirs, libs, opt_libs, [ext]) |
| if info is not None: |
| break |
| if not info: |
| log.info(' libraries %s not found in %s', ','.join(libs), |
| lib_dirs) |
| return info |
| |
| def check_libs2(self, lib_dirs, libs, opt_libs=[]): |
| """If static or shared libraries are available then return |
| their info dictionary. |
| |
| Checks each library for shared or static. |
| """ |
| exts = self.library_extensions() |
| info = self._check_libs(lib_dirs, libs, opt_libs, exts) |
| if not info: |
| log.info(' libraries %s not found in %s', ','.join(libs), |
| lib_dirs) |
| |
| return info |
| |
| def _find_lib(self, lib_dir, lib, exts): |
| assert is_string(lib_dir) |
| # under windows first try without 'lib' prefix |
| if sys.platform == 'win32': |
| lib_prefixes = ['', 'lib'] |
| else: |
| lib_prefixes = ['lib'] |
| # for each library name, see if we can find a file for it. |
| for ext in exts: |
| for prefix in lib_prefixes: |
| p = self.combine_paths(lib_dir, prefix + lib + ext) |
| if p: |
| break |
| if p: |
| assert len(p) == 1 |
| # ??? splitext on p[0] would do this for cygwin |
| # doesn't seem correct |
| if ext == '.dll.a': |
| lib += '.dll' |
| if ext == '.lib': |
| lib = prefix + lib |
| return lib |
| |
| return False |
| |
| def _find_libs(self, lib_dirs, libs, exts): |
| # make sure we preserve the order of libs, as it can be important |
| found_dirs, found_libs = [], [] |
| for lib in libs: |
| for lib_dir in lib_dirs: |
| found_lib = self._find_lib(lib_dir, lib, exts) |
| if found_lib: |
| found_libs.append(found_lib) |
| if lib_dir not in found_dirs: |
| found_dirs.append(lib_dir) |
| break |
| return found_dirs, found_libs |
| |
| def _check_libs(self, lib_dirs, libs, opt_libs, exts): |
| """Find mandatory and optional libs in expected paths. |
| |
| Missing optional libraries are silently forgotten. |
| """ |
| if not is_sequence(lib_dirs): |
| lib_dirs = [lib_dirs] |
| # First, try to find the mandatory libraries |
| found_dirs, found_libs = self._find_libs(lib_dirs, libs, exts) |
| if len(found_libs) > 0 and len(found_libs) == len(libs): |
| # Now, check for optional libraries |
| opt_found_dirs, opt_found_libs = self._find_libs(lib_dirs, opt_libs, exts) |
| found_libs.extend(opt_found_libs) |
| for lib_dir in opt_found_dirs: |
| if lib_dir not in found_dirs: |
| found_dirs.append(lib_dir) |
| info = {'libraries': found_libs, 'library_dirs': found_dirs} |
| return info |
| else: |
| return None |
| |
| def combine_paths(self, *args): |
| """Return a list of existing paths composed by all combinations |
| of items from the arguments. |
| """ |
| return combine_paths(*args) |
| |
| |
| class fft_opt_info(system_info): |
| |
| def calc_info(self): |
| info = {} |
| fftw_info = get_info('fftw3') or get_info('fftw2') or get_info('dfftw') |
| djbfft_info = get_info('djbfft') |
| if fftw_info: |
| dict_append(info, **fftw_info) |
| if djbfft_info: |
| dict_append(info, **djbfft_info) |
| self.set_info(**info) |
| return |
| |
| |
| class fftw_info(system_info): |
| #variables to override |
| section = 'fftw' |
| dir_env_var = 'FFTW' |
| notfounderror = FFTWNotFoundError |
| ver_info = [{'name':'fftw3', |
| 'libs':['fftw3'], |
| 'includes':['fftw3.h'], |
| 'macros':[('SCIPY_FFTW3_H', None)]}, |
| {'name':'fftw2', |
| 'libs':['rfftw', 'fftw'], |
| 'includes':['fftw.h', 'rfftw.h'], |
| 'macros':[('SCIPY_FFTW_H', None)]}] |
| |
| def calc_ver_info(self, ver_param): |
| """Returns True on successful version detection, else False""" |
| lib_dirs = self.get_lib_dirs() |
| incl_dirs = self.get_include_dirs() |
| |
| opt = self.get_option_single(self.section + '_libs', 'libraries') |
| libs = self.get_libs(opt, ver_param['libs']) |
| info = self.check_libs(lib_dirs, libs) |
| if info is not None: |
| flag = 0 |
| for d in incl_dirs: |
| if len(self.combine_paths(d, ver_param['includes'])) \ |
| == len(ver_param['includes']): |
| dict_append(info, include_dirs=[d]) |
| flag = 1 |
| break |
| if flag: |
| dict_append(info, define_macros=ver_param['macros']) |
| else: |
| info = None |
| if info is not None: |
| self.set_info(**info) |
| return True |
| else: |
| log.info(' %s not found' % (ver_param['name'])) |
| return False |
| |
| def calc_info(self): |
| for i in self.ver_info: |
| if self.calc_ver_info(i): |
| break |
| |
| |
| class fftw2_info(fftw_info): |
| #variables to override |
| section = 'fftw' |
| dir_env_var = 'FFTW' |
| notfounderror = FFTWNotFoundError |
| ver_info = [{'name':'fftw2', |
| 'libs':['rfftw', 'fftw'], |
| 'includes':['fftw.h', 'rfftw.h'], |
| 'macros':[('SCIPY_FFTW_H', None)]} |
| ] |
| |
| |
| class fftw3_info(fftw_info): |
| #variables to override |
| section = 'fftw3' |
| dir_env_var = 'FFTW3' |
| notfounderror = FFTWNotFoundError |
| ver_info = [{'name':'fftw3', |
| 'libs':['fftw3'], |
| 'includes':['fftw3.h'], |
| 'macros':[('SCIPY_FFTW3_H', None)]}, |
| ] |
| |
| |
| class fftw3_armpl_info(fftw_info): |
| section = 'fftw3' |
| dir_env_var = 'ARMPL_DIR' |
| notfounderror = FFTWNotFoundError |
| ver_info = [{'name': 'fftw3', |
| 'libs': ['armpl_lp64_mp'], |
| 'includes': ['fftw3.h'], |
| 'macros': [('SCIPY_FFTW3_H', None)]}] |
| |
| |
| class dfftw_info(fftw_info): |
| section = 'fftw' |
| dir_env_var = 'FFTW' |
| ver_info = [{'name':'dfftw', |
| 'libs':['drfftw', 'dfftw'], |
| 'includes':['dfftw.h', 'drfftw.h'], |
| 'macros':[('SCIPY_DFFTW_H', None)]}] |
| |
| |
| class sfftw_info(fftw_info): |
| section = 'fftw' |
| dir_env_var = 'FFTW' |
| ver_info = [{'name':'sfftw', |
| 'libs':['srfftw', 'sfftw'], |
| 'includes':['sfftw.h', 'srfftw.h'], |
| 'macros':[('SCIPY_SFFTW_H', None)]}] |
| |
| |
| class fftw_threads_info(fftw_info): |
| section = 'fftw' |
| dir_env_var = 'FFTW' |
| ver_info = [{'name':'fftw threads', |
| 'libs':['rfftw_threads', 'fftw_threads'], |
| 'includes':['fftw_threads.h', 'rfftw_threads.h'], |
| 'macros':[('SCIPY_FFTW_THREADS_H', None)]}] |
| |
| |
| class dfftw_threads_info(fftw_info): |
| section = 'fftw' |
| dir_env_var = 'FFTW' |
| ver_info = [{'name':'dfftw threads', |
| 'libs':['drfftw_threads', 'dfftw_threads'], |
| 'includes':['dfftw_threads.h', 'drfftw_threads.h'], |
| 'macros':[('SCIPY_DFFTW_THREADS_H', None)]}] |
| |
| |
| class sfftw_threads_info(fftw_info): |
| section = 'fftw' |
| dir_env_var = 'FFTW' |
| ver_info = [{'name':'sfftw threads', |
| 'libs':['srfftw_threads', 'sfftw_threads'], |
| 'includes':['sfftw_threads.h', 'srfftw_threads.h'], |
| 'macros':[('SCIPY_SFFTW_THREADS_H', None)]}] |
| |
| |
| class djbfft_info(system_info): |
| section = 'djbfft' |
| dir_env_var = 'DJBFFT' |
| notfounderror = DJBFFTNotFoundError |
| |
| def get_paths(self, section, key): |
| pre_dirs = system_info.get_paths(self, section, key) |
| dirs = [] |
| for d in pre_dirs: |
| dirs.extend(self.combine_paths(d, ['djbfft']) + [d]) |
| return [d for d in dirs if os.path.isdir(d)] |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| incl_dirs = self.get_include_dirs() |
| info = None |
| for d in lib_dirs: |
| p = self.combine_paths(d, ['djbfft.a']) |
| if p: |
| info = {'extra_objects': p} |
| break |
| p = self.combine_paths(d, ['libdjbfft.a', 'libdjbfft' + so_ext]) |
| if p: |
| info = {'libraries': ['djbfft'], 'library_dirs': [d]} |
| break |
| if info is None: |
| return |
| for d in incl_dirs: |
| if len(self.combine_paths(d, ['fftc8.h', 'fftfreq.h'])) == 2: |
| dict_append(info, include_dirs=[d], |
| define_macros=[('SCIPY_DJBFFT_H', None)]) |
| self.set_info(**info) |
| return |
| return |
| |
| |
| class mkl_info(system_info): |
| section = 'mkl' |
| dir_env_var = 'MKLROOT' |
| _lib_mkl = ['mkl_rt'] |
| |
| def get_mkl_rootdir(self): |
| mklroot = os.environ.get('MKLROOT', None) |
| if mklroot is not None: |
| return mklroot |
| paths = os.environ.get('LD_LIBRARY_PATH', '').split(os.pathsep) |
| ld_so_conf = '/etc/ld.so.conf' |
| if os.path.isfile(ld_so_conf): |
| with open(ld_so_conf) as f: |
| for d in f: |
| d = d.strip() |
| if d: |
| paths.append(d) |
| intel_mkl_dirs = [] |
| for path in paths: |
| path_atoms = path.split(os.sep) |
| for m in path_atoms: |
| if m.startswith('mkl'): |
| d = os.sep.join(path_atoms[:path_atoms.index(m) + 2]) |
| intel_mkl_dirs.append(d) |
| break |
| for d in paths: |
| dirs = glob(os.path.join(d, 'mkl', '*')) |
| dirs += glob(os.path.join(d, 'mkl*')) |
| for sub_dir in dirs: |
| if os.path.isdir(os.path.join(sub_dir, 'lib')): |
| return sub_dir |
| return None |
| |
| def __init__(self): |
| mklroot = self.get_mkl_rootdir() |
| if mklroot is None: |
| system_info.__init__(self) |
| else: |
| from .cpuinfo import cpu |
| if cpu.is_Itanium(): |
| plt = '64' |
| elif cpu.is_Intel() and cpu.is_64bit(): |
| plt = 'intel64' |
| else: |
| plt = '32' |
| system_info.__init__( |
| self, |
| default_lib_dirs=[os.path.join(mklroot, 'lib', plt)], |
| default_include_dirs=[os.path.join(mklroot, 'include')]) |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| incl_dirs = self.get_include_dirs() |
| opt = self.get_option_single('mkl_libs', 'libraries') |
| mkl_libs = self.get_libs(opt, self._lib_mkl) |
| info = self.check_libs2(lib_dirs, mkl_libs) |
| if info is None: |
| return |
| dict_append(info, |
| define_macros=[('SCIPY_MKL_H', None), |
| ('HAVE_CBLAS', None)], |
| include_dirs=incl_dirs) |
| if sys.platform == 'win32': |
| pass # win32 has no pthread library |
| else: |
| dict_append(info, libraries=['pthread']) |
| self.set_info(**info) |
| |
| |
| class lapack_mkl_info(mkl_info): |
| pass |
| |
| |
| class blas_mkl_info(mkl_info): |
| pass |
| |
| |
| class ssl2_info(system_info): |
| section = 'ssl2' |
| dir_env_var = 'SSL2_DIR' |
| # Multi-threaded version. Python itself must be built by Fujitsu compiler. |
| _lib_ssl2 = ['fjlapackexsve'] |
| # Single-threaded version |
| #_lib_ssl2 = ['fjlapacksve'] |
| |
| def get_tcsds_rootdir(self): |
| tcsdsroot = os.environ.get('TCSDS_PATH', None) |
| if tcsdsroot is not None: |
| return tcsdsroot |
| return None |
| |
| def __init__(self): |
| tcsdsroot = self.get_tcsds_rootdir() |
| if tcsdsroot is None: |
| system_info.__init__(self) |
| else: |
| system_info.__init__( |
| self, |
| default_lib_dirs=[os.path.join(tcsdsroot, 'lib64')], |
| default_include_dirs=[os.path.join(tcsdsroot, |
| 'clang-comp/include')]) |
| |
| def calc_info(self): |
| tcsdsroot = self.get_tcsds_rootdir() |
| |
| lib_dirs = self.get_lib_dirs() |
| if lib_dirs is None: |
| lib_dirs = os.path.join(tcsdsroot, 'lib64') |
| |
| incl_dirs = self.get_include_dirs() |
| if incl_dirs is None: |
| incl_dirs = os.path.join(tcsdsroot, 'clang-comp/include') |
| |
| ssl2_libs = self.get_libs('ssl2_libs', self._lib_ssl2) |
| |
| info = self.check_libs2(lib_dirs, ssl2_libs) |
| if info is None: |
| return |
| dict_append(info, |
| define_macros=[('HAVE_CBLAS', None), |
| ('HAVE_SSL2', 1)], |
| include_dirs=incl_dirs,) |
| self.set_info(**info) |
| |
| |
| class lapack_ssl2_info(ssl2_info): |
| pass |
| |
| |
| class blas_ssl2_info(ssl2_info): |
| pass |
| |
| |
| |
| class armpl_info(system_info): |
| section = 'armpl' |
| dir_env_var = 'ARMPL_DIR' |
| _lib_armpl = ['armpl_lp64_mp'] |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| incl_dirs = self.get_include_dirs() |
| armpl_libs = self.get_libs('armpl_libs', self._lib_armpl) |
| info = self.check_libs2(lib_dirs, armpl_libs) |
| if info is None: |
| return |
| dict_append(info, |
| define_macros=[('SCIPY_MKL_H', None), |
| ('HAVE_CBLAS', None)], |
| include_dirs=incl_dirs) |
| self.set_info(**info) |
| |
| class lapack_armpl_info(armpl_info): |
| pass |
| |
| class blas_armpl_info(armpl_info): |
| pass |
| |
| |
| class atlas_info(system_info): |
| section = 'atlas' |
| dir_env_var = 'ATLAS' |
| _lib_names = ['f77blas', 'cblas'] |
| if sys.platform[:7] == 'freebsd': |
| _lib_atlas = ['atlas_r'] |
| _lib_lapack = ['alapack_r'] |
| else: |
| _lib_atlas = ['atlas'] |
| _lib_lapack = ['lapack'] |
| |
| notfounderror = AtlasNotFoundError |
| |
| def get_paths(self, section, key): |
| pre_dirs = system_info.get_paths(self, section, key) |
| dirs = [] |
| for d in pre_dirs: |
| dirs.extend(self.combine_paths(d, ['atlas*', 'ATLAS*', |
| 'sse', '3dnow', 'sse2']) + [d]) |
| return [d for d in dirs if os.path.isdir(d)] |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| info = {} |
| opt = self.get_option_single('atlas_libs', 'libraries') |
| atlas_libs = self.get_libs(opt, self._lib_names + self._lib_atlas) |
| lapack_libs = self.get_libs('lapack_libs', self._lib_lapack) |
| atlas = None |
| lapack = None |
| atlas_1 = None |
| for d in lib_dirs: |
| atlas = self.check_libs2(d, atlas_libs, []) |
| if atlas is not None: |
| lib_dirs2 = [d] + self.combine_paths(d, ['atlas*', 'ATLAS*']) |
| lapack = self.check_libs2(lib_dirs2, lapack_libs, []) |
| if lapack is not None: |
| break |
| if atlas: |
| atlas_1 = atlas |
| log.info(self.__class__) |
| if atlas is None: |
| atlas = atlas_1 |
| if atlas is None: |
| return |
| include_dirs = self.get_include_dirs() |
| h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None]) |
| h = h[0] |
| if h: |
| h = os.path.dirname(h) |
| dict_append(info, include_dirs=[h]) |
| info['language'] = 'c' |
| if lapack is not None: |
| dict_append(info, **lapack) |
| dict_append(info, **atlas) |
| elif 'lapack_atlas' in atlas['libraries']: |
| dict_append(info, **atlas) |
| dict_append(info, |
| define_macros=[('ATLAS_WITH_LAPACK_ATLAS', None)]) |
| self.set_info(**info) |
| return |
| else: |
| dict_append(info, **atlas) |
| dict_append(info, define_macros=[('ATLAS_WITHOUT_LAPACK', None)]) |
| message = textwrap.dedent(""" |
| ********************************************************************* |
| Could not find lapack library within the ATLAS installation. |
| ********************************************************************* |
| """) |
| warnings.warn(message, stacklevel=2) |
| self.set_info(**info) |
| return |
| |
| # Check if lapack library is complete, only warn if it is not. |
| lapack_dir = lapack['library_dirs'][0] |
| lapack_name = lapack['libraries'][0] |
| lapack_lib = None |
| lib_prefixes = ['lib'] |
| if sys.platform == 'win32': |
| lib_prefixes.append('') |
| for e in self.library_extensions(): |
| for prefix in lib_prefixes: |
| fn = os.path.join(lapack_dir, prefix + lapack_name + e) |
| if os.path.exists(fn): |
| lapack_lib = fn |
| break |
| if lapack_lib: |
| break |
| if lapack_lib is not None: |
| sz = os.stat(lapack_lib)[6] |
| if sz <= 4000 * 1024: |
| message = textwrap.dedent(""" |
| ********************************************************************* |
| Lapack library (from ATLAS) is probably incomplete: |
| size of %s is %sk (expected >4000k) |
| |
| Follow the instructions in the KNOWN PROBLEMS section of the file |
| numpy/INSTALL.txt. |
| ********************************************************************* |
| """) % (lapack_lib, sz / 1024) |
| warnings.warn(message, stacklevel=2) |
| else: |
| info['language'] = 'f77' |
| |
| atlas_version, atlas_extra_info = get_atlas_version(**atlas) |
| dict_append(info, **atlas_extra_info) |
| |
| self.set_info(**info) |
| |
| |
| class atlas_blas_info(atlas_info): |
| _lib_names = ['f77blas', 'cblas'] |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| info = {} |
| opt = self.get_option_single('atlas_libs', 'libraries') |
| atlas_libs = self.get_libs(opt, self._lib_names + self._lib_atlas) |
| atlas = self.check_libs2(lib_dirs, atlas_libs, []) |
| if atlas is None: |
| return |
| include_dirs = self.get_include_dirs() |
| h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None]) |
| h = h[0] |
| if h: |
| h = os.path.dirname(h) |
| dict_append(info, include_dirs=[h]) |
| info['language'] = 'c' |
| info['define_macros'] = [('HAVE_CBLAS', None)] |
| |
| atlas_version, atlas_extra_info = get_atlas_version(**atlas) |
| dict_append(atlas, **atlas_extra_info) |
| |
| dict_append(info, **atlas) |
| |
| self.set_info(**info) |
| return |
| |
| |
| class atlas_threads_info(atlas_info): |
| dir_env_var = ['PTATLAS', 'ATLAS'] |
| _lib_names = ['ptf77blas', 'ptcblas'] |
| |
| |
| class atlas_blas_threads_info(atlas_blas_info): |
| dir_env_var = ['PTATLAS', 'ATLAS'] |
| _lib_names = ['ptf77blas', 'ptcblas'] |
| |
| |
| class lapack_atlas_info(atlas_info): |
| _lib_names = ['lapack_atlas'] + atlas_info._lib_names |
| |
| |
| class lapack_atlas_threads_info(atlas_threads_info): |
| _lib_names = ['lapack_atlas'] + atlas_threads_info._lib_names |
| |
| |
| class atlas_3_10_info(atlas_info): |
| _lib_names = ['satlas'] |
| _lib_atlas = _lib_names |
| _lib_lapack = _lib_names |
| |
| |
| class atlas_3_10_blas_info(atlas_3_10_info): |
| _lib_names = ['satlas'] |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| info = {} |
| opt = self.get_option_single('atlas_lib', 'libraries') |
| atlas_libs = self.get_libs(opt, self._lib_names) |
| atlas = self.check_libs2(lib_dirs, atlas_libs, []) |
| if atlas is None: |
| return |
| include_dirs = self.get_include_dirs() |
| h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None]) |
| h = h[0] |
| if h: |
| h = os.path.dirname(h) |
| dict_append(info, include_dirs=[h]) |
| info['language'] = 'c' |
| info['define_macros'] = [('HAVE_CBLAS', None)] |
| |
| atlas_version, atlas_extra_info = get_atlas_version(**atlas) |
| dict_append(atlas, **atlas_extra_info) |
| |
| dict_append(info, **atlas) |
| |
| self.set_info(**info) |
| return |
| |
| |
| class atlas_3_10_threads_info(atlas_3_10_info): |
| dir_env_var = ['PTATLAS', 'ATLAS'] |
| _lib_names = ['tatlas'] |
| _lib_atlas = _lib_names |
| _lib_lapack = _lib_names |
| |
| |
| class atlas_3_10_blas_threads_info(atlas_3_10_blas_info): |
| dir_env_var = ['PTATLAS', 'ATLAS'] |
| _lib_names = ['tatlas'] |
| |
| |
| class lapack_atlas_3_10_info(atlas_3_10_info): |
| pass |
| |
| |
| class lapack_atlas_3_10_threads_info(atlas_3_10_threads_info): |
| pass |
| |
| |
| class lapack_info(system_info): |
| section = 'lapack' |
| dir_env_var = 'LAPACK' |
| _lib_names = ['lapack'] |
| notfounderror = LapackNotFoundError |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| |
| opt = self.get_option_single('lapack_libs', 'libraries') |
| lapack_libs = self.get_libs(opt, self._lib_names) |
| info = self.check_libs(lib_dirs, lapack_libs, []) |
| if info is None: |
| return |
| info['language'] = 'f77' |
| self.set_info(**info) |
| |
| |
| class lapack_src_info(system_info): |
| # LAPACK_SRC is deprecated, please do not use this! |
| # Build or install a BLAS library via your package manager or from |
| # source separately. |
| section = 'lapack_src' |
| dir_env_var = 'LAPACK_SRC' |
| notfounderror = LapackSrcNotFoundError |
| |
| def get_paths(self, section, key): |
| pre_dirs = system_info.get_paths(self, section, key) |
| dirs = [] |
| for d in pre_dirs: |
| dirs.extend([d] + self.combine_paths(d, ['LAPACK*/SRC', 'SRC'])) |
| return [d for d in dirs if os.path.isdir(d)] |
| |
| def calc_info(self): |
| src_dirs = self.get_src_dirs() |
| src_dir = '' |
| for d in src_dirs: |
| if os.path.isfile(os.path.join(d, 'dgesv.f')): |
| src_dir = d |
| break |
| if not src_dir: |
| #XXX: Get sources from netlib. May be ask first. |
| return |
| # The following is extracted from LAPACK-3.0/SRC/Makefile. |
| # Added missing names from lapack-lite-3.1.1/SRC/Makefile |
| # while keeping removed names for Lapack-3.0 compatibility. |
| allaux = ''' |
| ilaenv ieeeck lsame lsamen xerbla |
| iparmq |
| ''' # *.f |
| laux = ''' |
| bdsdc bdsqr disna labad lacpy ladiv lae2 laebz laed0 laed1 |
| laed2 laed3 laed4 laed5 laed6 laed7 laed8 laed9 laeda laev2 |
| lagtf lagts lamch lamrg lanst lapy2 lapy3 larnv larrb larre |
| larrf lartg laruv las2 lascl lasd0 lasd1 lasd2 lasd3 lasd4 |
| lasd5 lasd6 lasd7 lasd8 lasd9 lasda lasdq lasdt laset lasq1 |
| lasq2 lasq3 lasq4 lasq5 lasq6 lasr lasrt lassq lasv2 pttrf |
| stebz stedc steqr sterf |
| |
| larra larrc larrd larr larrk larrj larrr laneg laisnan isnan |
| lazq3 lazq4 |
| ''' # [s|d]*.f |
| lasrc = ''' |
| gbbrd gbcon gbequ gbrfs gbsv gbsvx gbtf2 gbtrf gbtrs gebak |
| gebal gebd2 gebrd gecon geequ gees geesx geev geevx gegs gegv |
| gehd2 gehrd gelq2 gelqf gels gelsd gelss gelsx gelsy geql2 |
| geqlf geqp3 geqpf geqr2 geqrf gerfs gerq2 gerqf gesc2 gesdd |
| gesv gesvd gesvx getc2 getf2 getrf getri getrs ggbak ggbal |
| gges ggesx ggev ggevx ggglm gghrd gglse ggqrf ggrqf ggsvd |
| ggsvp gtcon gtrfs gtsv gtsvx gttrf gttrs gtts2 hgeqz hsein |
| hseqr labrd lacon laein lags2 lagtm lahqr lahrd laic1 lals0 |
| lalsa lalsd langb lange langt lanhs lansb lansp lansy lantb |
| lantp lantr lapll lapmt laqgb laqge laqp2 laqps laqsb laqsp |
| laqsy lar1v lar2v larf larfb larfg larft larfx largv larrv |
| lartv larz larzb larzt laswp lasyf latbs latdf latps latrd |
| latrs latrz latzm lauu2 lauum pbcon pbequ pbrfs pbstf pbsv |
| pbsvx pbtf2 pbtrf pbtrs pocon poequ porfs posv posvx potf2 |
| potrf potri potrs ppcon ppequ pprfs ppsv ppsvx pptrf pptri |
| pptrs ptcon pteqr ptrfs ptsv ptsvx pttrs ptts2 spcon sprfs |
| spsv spsvx sptrf sptri sptrs stegr stein sycon syrfs sysv |
| sysvx sytf2 sytrf sytri sytrs tbcon tbrfs tbtrs tgevc tgex2 |
| tgexc tgsen tgsja tgsna tgsy2 tgsyl tpcon tprfs tptri tptrs |
| trcon trevc trexc trrfs trsen trsna trsyl trti2 trtri trtrs |
| tzrqf tzrzf |
| |
| lacn2 lahr2 stemr laqr0 laqr1 laqr2 laqr3 laqr4 laqr5 |
| ''' # [s|c|d|z]*.f |
| sd_lasrc = ''' |
| laexc lag2 lagv2 laln2 lanv2 laqtr lasy2 opgtr opmtr org2l |
| org2r orgbr orghr orgl2 orglq orgql orgqr orgr2 orgrq orgtr |
| orm2l orm2r ormbr ormhr orml2 ormlq ormql ormqr ormr2 ormr3 |
| ormrq ormrz ormtr rscl sbev sbevd sbevx sbgst sbgv sbgvd sbgvx |
| sbtrd spev spevd spevx spgst spgv spgvd spgvx sptrd stev stevd |
| stevr stevx syev syevd syevr syevx sygs2 sygst sygv sygvd |
| sygvx sytd2 sytrd |
| ''' # [s|d]*.f |
| cz_lasrc = ''' |
| bdsqr hbev hbevd hbevx hbgst hbgv hbgvd hbgvx hbtrd hecon heev |
| heevd heevr heevx hegs2 hegst hegv hegvd hegvx herfs hesv |
| hesvx hetd2 hetf2 hetrd hetrf hetri hetrs hpcon hpev hpevd |
| hpevx hpgst hpgv hpgvd hpgvx hprfs hpsv hpsvx hptrd hptrf |
| hptri hptrs lacgv lacp2 lacpy lacrm lacrt ladiv laed0 laed7 |
| laed8 laesy laev2 lahef lanhb lanhe lanhp lanht laqhb laqhe |
| laqhp larcm larnv lartg lascl laset lasr lassq pttrf rot spmv |
| spr stedc steqr symv syr ung2l ung2r ungbr unghr ungl2 unglq |
| ungql ungqr ungr2 ungrq ungtr unm2l unm2r unmbr unmhr unml2 |
| unmlq unmql unmqr unmr2 unmr3 unmrq unmrz unmtr upgtr upmtr |
| ''' # [c|z]*.f |
| ####### |
| sclaux = laux + ' econd ' # s*.f |
| dzlaux = laux + ' secnd ' # d*.f |
| slasrc = lasrc + sd_lasrc # s*.f |
| dlasrc = lasrc + sd_lasrc # d*.f |
| clasrc = lasrc + cz_lasrc + ' srot srscl ' # c*.f |
| zlasrc = lasrc + cz_lasrc + ' drot drscl ' # z*.f |
| oclasrc = ' icmax1 scsum1 ' # *.f |
| ozlasrc = ' izmax1 dzsum1 ' # *.f |
| sources = ['s%s.f' % f for f in (sclaux + slasrc).split()] \ |
| + ['d%s.f' % f for f in (dzlaux + dlasrc).split()] \ |
| + ['c%s.f' % f for f in (clasrc).split()] \ |
| + ['z%s.f' % f for f in (zlasrc).split()] \ |
| + ['%s.f' % f for f in (allaux + oclasrc + ozlasrc).split()] |
| sources = [os.path.join(src_dir, f) for f in sources] |
| # Lapack 3.1: |
| src_dir2 = os.path.join(src_dir, '..', 'INSTALL') |
| sources += [os.path.join(src_dir2, p + 'lamch.f') for p in 'sdcz'] |
| # Lapack 3.2.1: |
| sources += [os.path.join(src_dir, p + 'larfp.f') for p in 'sdcz'] |
| sources += [os.path.join(src_dir, 'ila' + p + 'lr.f') for p in 'sdcz'] |
| sources += [os.path.join(src_dir, 'ila' + p + 'lc.f') for p in 'sdcz'] |
| # Should we check here actual existence of source files? |
| # Yes, the file listing is different between 3.0 and 3.1 |
| # versions. |
| sources = [f for f in sources if os.path.isfile(f)] |
| info = {'sources': sources, 'language': 'f77'} |
| self.set_info(**info) |
| |
| atlas_version_c_text = r''' |
| /* This file is generated from numpy/distutils/system_info.py */ |
| void ATL_buildinfo(void); |
| int main(void) { |
| ATL_buildinfo(); |
| return 0; |
| } |
| ''' |
| |
| _cached_atlas_version = {} |
| |
| |
| def get_atlas_version(**config): |
| libraries = config.get('libraries', []) |
| library_dirs = config.get('library_dirs', []) |
| key = (tuple(libraries), tuple(library_dirs)) |
| if key in _cached_atlas_version: |
| return _cached_atlas_version[key] |
| c = cmd_config(Distribution()) |
| atlas_version = None |
| info = {} |
| try: |
| s, o = c.get_output(atlas_version_c_text, |
| libraries=libraries, library_dirs=library_dirs, |
| ) |
| if s and re.search(r'undefined reference to `_gfortran', o, re.M): |
| s, o = c.get_output(atlas_version_c_text, |
| libraries=libraries + ['gfortran'], |
| library_dirs=library_dirs, |
| ) |
| if not s: |
| warnings.warn(textwrap.dedent(""" |
| ***************************************************** |
| Linkage with ATLAS requires gfortran. Use |
| |
| python setup.py config_fc --fcompiler=gnu95 ... |
| |
| when building extension libraries that use ATLAS. |
| Make sure that -lgfortran is used for C++ extensions. |
| ***************************************************** |
| """), stacklevel=2) |
| dict_append(info, language='f90', |
| define_macros=[('ATLAS_REQUIRES_GFORTRAN', None)]) |
| except Exception: # failed to get version from file -- maybe on Windows |
| # look at directory name |
| for o in library_dirs: |
| m = re.search(r'ATLAS_(?P<version>\d+[.]\d+[.]\d+)_', o) |
| if m: |
| atlas_version = m.group('version') |
| if atlas_version is not None: |
| break |
| |
| # final choice --- look at ATLAS_VERSION environment |
| # variable |
| if atlas_version is None: |
| atlas_version = os.environ.get('ATLAS_VERSION', None) |
| if atlas_version: |
| dict_append(info, define_macros=[( |
| 'ATLAS_INFO', _c_string_literal(atlas_version)) |
| ]) |
| else: |
| dict_append(info, define_macros=[('NO_ATLAS_INFO', -1)]) |
| return atlas_version or '?.?.?', info |
| |
| if not s: |
| m = re.search(r'ATLAS version (?P<version>\d+[.]\d+[.]\d+)', o) |
| if m: |
| atlas_version = m.group('version') |
| if atlas_version is None: |
| if re.search(r'undefined symbol: ATL_buildinfo', o, re.M): |
| atlas_version = '3.2.1_pre3.3.6' |
| else: |
| log.info('Status: %d', s) |
| log.info('Output: %s', o) |
| |
| elif atlas_version == '3.2.1_pre3.3.6': |
| dict_append(info, define_macros=[('NO_ATLAS_INFO', -2)]) |
| else: |
| dict_append(info, define_macros=[( |
| 'ATLAS_INFO', _c_string_literal(atlas_version)) |
| ]) |
| result = _cached_atlas_version[key] = atlas_version, info |
| return result |
| |
| |
| class lapack_opt_info(system_info): |
| notfounderror = LapackNotFoundError |
| |
| # List of all known LAPACK libraries, in the default order |
| lapack_order = ['armpl', 'mkl', 'ssl2', 'openblas', 'flame', |
| 'accelerate', 'atlas', 'lapack'] |
| order_env_var_name = 'NPY_LAPACK_ORDER' |
| |
| def _calc_info_armpl(self): |
| info = get_info('lapack_armpl') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_mkl(self): |
| info = get_info('lapack_mkl') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_ssl2(self): |
| info = get_info('lapack_ssl2') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_openblas(self): |
| info = get_info('openblas_lapack') |
| if info: |
| self.set_info(**info) |
| return True |
| info = get_info('openblas_clapack') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_flame(self): |
| info = get_info('flame') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_atlas(self): |
| info = get_info('atlas_3_10_threads') |
| if not info: |
| info = get_info('atlas_3_10') |
| if not info: |
| info = get_info('atlas_threads') |
| if not info: |
| info = get_info('atlas') |
| if info: |
| # Figure out if ATLAS has lapack... |
| # If not we need the lapack library, but not BLAS! |
| l = info.get('define_macros', []) |
| if ('ATLAS_WITH_LAPACK_ATLAS', None) in l \ |
| or ('ATLAS_WITHOUT_LAPACK', None) in l: |
| # Get LAPACK (with possible warnings) |
| # If not found we don't accept anything |
| # since we can't use ATLAS with LAPACK! |
| lapack_info = self._get_info_lapack() |
| if not lapack_info: |
| return False |
| dict_append(info, **lapack_info) |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_accelerate(self): |
| info = get_info('accelerate') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _get_info_blas(self): |
| # Default to get the optimized BLAS implementation |
| info = get_info('blas_opt') |
| if not info: |
| warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=3) |
| info_src = get_info('blas_src') |
| if not info_src: |
| warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=3) |
| return {} |
| dict_append(info, libraries=[('fblas_src', info_src)]) |
| return info |
| |
| def _get_info_lapack(self): |
| info = get_info('lapack') |
| if not info: |
| warnings.warn(LapackNotFoundError.__doc__ or '', stacklevel=3) |
| info_src = get_info('lapack_src') |
| if not info_src: |
| warnings.warn(LapackSrcNotFoundError.__doc__ or '', stacklevel=3) |
| return {} |
| dict_append(info, libraries=[('flapack_src', info_src)]) |
| return info |
| |
| def _calc_info_lapack(self): |
| info = self._get_info_lapack() |
| if info: |
| info_blas = self._get_info_blas() |
| dict_append(info, **info_blas) |
| dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_from_envvar(self): |
| info = {} |
| info['language'] = 'f77' |
| info['libraries'] = [] |
| info['include_dirs'] = [] |
| info['define_macros'] = [] |
| info['extra_link_args'] = os.environ['NPY_LAPACK_LIBS'].split() |
| self.set_info(**info) |
| return True |
| |
| def _calc_info(self, name): |
| return getattr(self, '_calc_info_{}'.format(name))() |
| |
| def calc_info(self): |
| lapack_order, unknown_order = _parse_env_order(self.lapack_order, self.order_env_var_name) |
| if len(unknown_order) > 0: |
| raise ValueError("lapack_opt_info user defined " |
| "LAPACK order has unacceptable " |
| "values: {}".format(unknown_order)) |
| |
| if 'NPY_LAPACK_LIBS' in os.environ: |
| # Bypass autodetection, set language to F77 and use env var linker |
| # flags directly |
| self._calc_info_from_envvar() |
| return |
| |
| for lapack in lapack_order: |
| if self._calc_info(lapack): |
| return |
| |
| if 'lapack' not in lapack_order: |
| # Since the user may request *not* to use any library, we still need |
| # to raise warnings to signal missing packages! |
| warnings.warn(LapackNotFoundError.__doc__ or '', stacklevel=2) |
| warnings.warn(LapackSrcNotFoundError.__doc__ or '', stacklevel=2) |
| |
| |
| class _ilp64_opt_info_mixin: |
| symbol_suffix = None |
| symbol_prefix = None |
| |
| def _check_info(self, info): |
| macros = dict(info.get('define_macros', [])) |
| prefix = macros.get('BLAS_SYMBOL_PREFIX', '') |
| suffix = macros.get('BLAS_SYMBOL_SUFFIX', '') |
| |
| if self.symbol_prefix not in (None, prefix): |
| return False |
| |
| if self.symbol_suffix not in (None, suffix): |
| return False |
| |
| return bool(info) |
| |
| |
| class lapack_ilp64_opt_info(lapack_opt_info, _ilp64_opt_info_mixin): |
| notfounderror = LapackILP64NotFoundError |
| lapack_order = ['openblas64_', 'openblas_ilp64'] |
| order_env_var_name = 'NPY_LAPACK_ILP64_ORDER' |
| |
| def _calc_info(self, name): |
| info = get_info(name + '_lapack') |
| if self._check_info(info): |
| self.set_info(**info) |
| return True |
| return False |
| |
| |
| class lapack_ilp64_plain_opt_info(lapack_ilp64_opt_info): |
| # Same as lapack_ilp64_opt_info, but fix symbol names |
| symbol_prefix = '' |
| symbol_suffix = '' |
| |
| |
| class lapack64__opt_info(lapack_ilp64_opt_info): |
| symbol_prefix = '' |
| symbol_suffix = '64_' |
| |
| |
| class blas_opt_info(system_info): |
| notfounderror = BlasNotFoundError |
| # List of all known BLAS libraries, in the default order |
| |
| blas_order = ['armpl', 'mkl', 'ssl2', 'blis', 'openblas', |
| 'accelerate', 'atlas', 'blas'] |
| order_env_var_name = 'NPY_BLAS_ORDER' |
| |
| def _calc_info_armpl(self): |
| info = get_info('blas_armpl') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_mkl(self): |
| info = get_info('blas_mkl') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_ssl2(self): |
| info = get_info('blas_ssl2') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_blis(self): |
| info = get_info('blis') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_openblas(self): |
| info = get_info('openblas') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_atlas(self): |
| info = get_info('atlas_3_10_blas_threads') |
| if not info: |
| info = get_info('atlas_3_10_blas') |
| if not info: |
| info = get_info('atlas_blas_threads') |
| if not info: |
| info = get_info('atlas_blas') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_accelerate(self): |
| info = get_info('accelerate') |
| if info: |
| self.set_info(**info) |
| return True |
| return False |
| |
| def _calc_info_blas(self): |
| # Warn about a non-optimized BLAS library |
| warnings.warn(BlasOptNotFoundError.__doc__ or '', stacklevel=3) |
| info = {} |
| dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) |
| |
| blas = get_info('blas') |
| if blas: |
| dict_append(info, **blas) |
| else: |
| # Not even BLAS was found! |
| warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=3) |
| |
| blas_src = get_info('blas_src') |
| if not blas_src: |
| warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=3) |
| return False |
| dict_append(info, libraries=[('fblas_src', blas_src)]) |
| |
| self.set_info(**info) |
| return True |
| |
| def _calc_info_from_envvar(self): |
| info = {} |
| info['language'] = 'f77' |
| info['libraries'] = [] |
| info['include_dirs'] = [] |
| info['define_macros'] = [] |
| info['extra_link_args'] = os.environ['NPY_BLAS_LIBS'].split() |
| if 'NPY_CBLAS_LIBS' in os.environ: |
| info['define_macros'].append(('HAVE_CBLAS', None)) |
| info['extra_link_args'].extend( |
| os.environ['NPY_CBLAS_LIBS'].split()) |
| self.set_info(**info) |
| return True |
| |
| def _calc_info(self, name): |
| return getattr(self, '_calc_info_{}'.format(name))() |
| |
| def calc_info(self): |
| blas_order, unknown_order = _parse_env_order(self.blas_order, self.order_env_var_name) |
| if len(unknown_order) > 0: |
| raise ValueError("blas_opt_info user defined BLAS order has unacceptable values: {}".format(unknown_order)) |
| |
| if 'NPY_BLAS_LIBS' in os.environ: |
| # Bypass autodetection, set language to F77 and use env var linker |
| # flags directly |
| self._calc_info_from_envvar() |
| return |
| |
| for blas in blas_order: |
| if self._calc_info(blas): |
| return |
| |
| if 'blas' not in blas_order: |
| # Since the user may request *not* to use any library, we still need |
| # to raise warnings to signal missing packages! |
| warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=2) |
| warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=2) |
| |
| |
| class blas_ilp64_opt_info(blas_opt_info, _ilp64_opt_info_mixin): |
| notfounderror = BlasILP64NotFoundError |
| blas_order = ['openblas64_', 'openblas_ilp64'] |
| order_env_var_name = 'NPY_BLAS_ILP64_ORDER' |
| |
| def _calc_info(self, name): |
| info = get_info(name) |
| if self._check_info(info): |
| self.set_info(**info) |
| return True |
| return False |
| |
| |
| class blas_ilp64_plain_opt_info(blas_ilp64_opt_info): |
| symbol_prefix = '' |
| symbol_suffix = '' |
| |
| |
| class blas64__opt_info(blas_ilp64_opt_info): |
| symbol_prefix = '' |
| symbol_suffix = '64_' |
| |
| |
| class cblas_info(system_info): |
| section = 'cblas' |
| dir_env_var = 'CBLAS' |
| # No default as it's used only in blas_info |
| _lib_names = [] |
| notfounderror = BlasNotFoundError |
| |
| |
| class blas_info(system_info): |
| section = 'blas' |
| dir_env_var = 'BLAS' |
| _lib_names = ['blas'] |
| notfounderror = BlasNotFoundError |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| opt = self.get_option_single('blas_libs', 'libraries') |
| blas_libs = self.get_libs(opt, self._lib_names) |
| info = self.check_libs(lib_dirs, blas_libs, []) |
| if info is None: |
| return |
| else: |
| info['include_dirs'] = self.get_include_dirs() |
| if platform.system() == 'Windows': |
| # The check for windows is needed because get_cblas_libs uses the |
| # same compiler that was used to compile Python and msvc is |
| # often not installed when mingw is being used. This rough |
| # treatment is not desirable, but windows is tricky. |
| info['language'] = 'f77' # XXX: is it generally true? |
| # If cblas is given as an option, use those |
| cblas_info_obj = cblas_info() |
| cblas_opt = cblas_info_obj.get_option_single('cblas_libs', 'libraries') |
| cblas_libs = cblas_info_obj.get_libs(cblas_opt, None) |
| if cblas_libs: |
| info['libraries'] = cblas_libs + blas_libs |
| info['define_macros'] = [('HAVE_CBLAS', None)] |
| else: |
| lib = self.get_cblas_libs(info) |
| if lib is not None: |
| info['language'] = 'c' |
| info['libraries'] = lib |
| info['define_macros'] = [('HAVE_CBLAS', None)] |
| self.set_info(**info) |
| |
| def get_cblas_libs(self, info): |
| """ Check whether we can link with CBLAS interface |
| |
| This method will search through several combinations of libraries |
| to check whether CBLAS is present: |
| |
| 1. Libraries in ``info['libraries']``, as is |
| 2. As 1. but also explicitly adding ``'cblas'`` as a library |
| 3. As 1. but also explicitly adding ``'blas'`` as a library |
| 4. Check only library ``'cblas'`` |
| 5. Check only library ``'blas'`` |
| |
| Parameters |
| ---------- |
| info : dict |
| system information dictionary for compilation and linking |
| |
| Returns |
| ------- |
| libraries : list of str or None |
| a list of libraries that enables the use of CBLAS interface. |
| Returns None if not found or a compilation error occurs. |
| |
| Since 1.17 returns a list. |
| """ |
| # primitive cblas check by looking for the header and trying to link |
| # cblas or blas |
| c = customized_ccompiler() |
| tmpdir = tempfile.mkdtemp() |
| s = textwrap.dedent("""\ |
| #include <cblas.h> |
| int main(int argc, const char *argv[]) |
| { |
| double a[4] = {1,2,3,4}; |
| double b[4] = {5,6,7,8}; |
| return cblas_ddot(4, a, 1, b, 1) > 10; |
| }""") |
| src = os.path.join(tmpdir, 'source.c') |
| try: |
| with open(src, 'w') as f: |
| f.write(s) |
| |
| try: |
| # check we can compile (find headers) |
| obj = c.compile([src], output_dir=tmpdir, |
| include_dirs=self.get_include_dirs()) |
| except (distutils.ccompiler.CompileError, distutils.ccompiler.LinkError): |
| return None |
| |
| # check we can link (find library) |
| # some systems have separate cblas and blas libs. |
| for libs in [info['libraries'], ['cblas'] + info['libraries'], |
| ['blas'] + info['libraries'], ['cblas'], ['blas']]: |
| try: |
| c.link_executable(obj, os.path.join(tmpdir, "a.out"), |
| libraries=libs, |
| library_dirs=info['library_dirs'], |
| extra_postargs=info.get('extra_link_args', [])) |
| return libs |
| except distutils.ccompiler.LinkError: |
| pass |
| finally: |
| shutil.rmtree(tmpdir) |
| return None |
| |
| |
| class openblas_info(blas_info): |
| section = 'openblas' |
| dir_env_var = 'OPENBLAS' |
| _lib_names = ['openblas'] |
| _require_symbols = [] |
| notfounderror = BlasNotFoundError |
| |
| @property |
| def symbol_prefix(self): |
| try: |
| return self.cp.get(self.section, 'symbol_prefix') |
| except NoOptionError: |
| return '' |
| |
| @property |
| def symbol_suffix(self): |
| try: |
| return self.cp.get(self.section, 'symbol_suffix') |
| except NoOptionError: |
| return '' |
| |
| def _calc_info(self): |
| c = customized_ccompiler() |
| |
| lib_dirs = self.get_lib_dirs() |
| |
| # Prefer to use libraries over openblas_libs |
| opt = self.get_option_single('openblas_libs', 'libraries') |
| openblas_libs = self.get_libs(opt, self._lib_names) |
| |
| info = self.check_libs(lib_dirs, openblas_libs, []) |
| |
| if c.compiler_type == "msvc" and info is None: |
| from numpy.distutils.fcompiler import new_fcompiler |
| f = new_fcompiler(c_compiler=c) |
| if f and f.compiler_type == 'gnu95': |
| # Try gfortran-compatible library files |
| info = self.check_msvc_gfortran_libs(lib_dirs, openblas_libs) |
| # Skip lapack check, we'd need build_ext to do it |
| skip_symbol_check = True |
| elif info: |
| skip_symbol_check = False |
| info['language'] = 'c' |
| |
| if info is None: |
| return None |
| |
| # Add extra info for OpenBLAS |
| extra_info = self.calc_extra_info() |
| dict_append(info, **extra_info) |
| |
| if not (skip_symbol_check or self.check_symbols(info)): |
| return None |
| |
| info['define_macros'] = [('HAVE_CBLAS', None)] |
| if self.symbol_prefix: |
| info['define_macros'] += [('BLAS_SYMBOL_PREFIX', self.symbol_prefix)] |
| if self.symbol_suffix: |
| info['define_macros'] += [('BLAS_SYMBOL_SUFFIX', self.symbol_suffix)] |
| |
| return info |
| |
| def calc_info(self): |
| info = self._calc_info() |
| if info is not None: |
| self.set_info(**info) |
| |
| def check_msvc_gfortran_libs(self, library_dirs, libraries): |
| # First, find the full path to each library directory |
| library_paths = [] |
| for library in libraries: |
| for library_dir in library_dirs: |
| # MinGW static ext will be .a |
| fullpath = os.path.join(library_dir, library + '.a') |
| if os.path.isfile(fullpath): |
| library_paths.append(fullpath) |
| break |
| else: |
| return None |
| |
| # Generate numpy.distutils virtual static library file |
| basename = self.__class__.__name__ |
| tmpdir = os.path.join(os.getcwd(), 'build', basename) |
| if not os.path.isdir(tmpdir): |
| os.makedirs(tmpdir) |
| |
| info = {'library_dirs': [tmpdir], |
| 'libraries': [basename], |
| 'language': 'f77'} |
| |
| fake_lib_file = os.path.join(tmpdir, basename + '.fobjects') |
| fake_clib_file = os.path.join(tmpdir, basename + '.cobjects') |
| with open(fake_lib_file, 'w') as f: |
| f.write("\n".join(library_paths)) |
| with open(fake_clib_file, 'w') as f: |
| pass |
| |
| return info |
| |
| def check_symbols(self, info): |
| res = False |
| c = customized_ccompiler() |
| |
| tmpdir = tempfile.mkdtemp() |
| |
| prototypes = "\n".join("void %s%s%s();" % (self.symbol_prefix, |
| symbol_name, |
| self.symbol_suffix) |
| for symbol_name in self._require_symbols) |
| calls = "\n".join("%s%s%s();" % (self.symbol_prefix, |
| symbol_name, |
| self.symbol_suffix) |
| for symbol_name in self._require_symbols) |
| s = textwrap.dedent("""\ |
| %(prototypes)s |
| int main(int argc, const char *argv[]) |
| { |
| %(calls)s |
| return 0; |
| }""") % dict(prototypes=prototypes, calls=calls) |
| src = os.path.join(tmpdir, 'source.c') |
| out = os.path.join(tmpdir, 'a.out') |
| # Add the additional "extra" arguments |
| try: |
| extra_args = info['extra_link_args'] |
| except Exception: |
| extra_args = [] |
| try: |
| with open(src, 'w') as f: |
| f.write(s) |
| obj = c.compile([src], output_dir=tmpdir) |
| try: |
| c.link_executable(obj, out, libraries=info['libraries'], |
| library_dirs=info['library_dirs'], |
| extra_postargs=extra_args) |
| res = True |
| except distutils.ccompiler.LinkError: |
| res = False |
| finally: |
| shutil.rmtree(tmpdir) |
| return res |
| |
| class openblas_lapack_info(openblas_info): |
| section = 'openblas' |
| dir_env_var = 'OPENBLAS' |
| _lib_names = ['openblas'] |
| _require_symbols = ['zungqr_'] |
| notfounderror = BlasNotFoundError |
| |
| class openblas_clapack_info(openblas_lapack_info): |
| _lib_names = ['openblas', 'lapack'] |
| |
| class openblas_ilp64_info(openblas_info): |
| section = 'openblas_ilp64' |
| dir_env_var = 'OPENBLAS_ILP64' |
| _lib_names = ['openblas64'] |
| _require_symbols = ['dgemm_', 'cblas_dgemm'] |
| notfounderror = BlasILP64NotFoundError |
| |
| def _calc_info(self): |
| info = super()._calc_info() |
| if info is not None: |
| info['define_macros'] += [('HAVE_BLAS_ILP64', None)] |
| return info |
| |
| class openblas_ilp64_lapack_info(openblas_ilp64_info): |
| _require_symbols = ['dgemm_', 'cblas_dgemm', 'zungqr_', 'LAPACKE_zungqr'] |
| |
| def _calc_info(self): |
| info = super()._calc_info() |
| if info: |
| info['define_macros'] += [('HAVE_LAPACKE', None)] |
| return info |
| |
| class openblas64__info(openblas_ilp64_info): |
| # ILP64 Openblas, with default symbol suffix |
| section = 'openblas64_' |
| dir_env_var = 'OPENBLAS64_' |
| _lib_names = ['openblas64_'] |
| symbol_suffix = '64_' |
| symbol_prefix = '' |
| |
| class openblas64__lapack_info(openblas_ilp64_lapack_info, openblas64__info): |
| pass |
| |
| class blis_info(blas_info): |
| section = 'blis' |
| dir_env_var = 'BLIS' |
| _lib_names = ['blis'] |
| notfounderror = BlasNotFoundError |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| opt = self.get_option_single('blis_libs', 'libraries') |
| blis_libs = self.get_libs(opt, self._lib_names) |
| info = self.check_libs2(lib_dirs, blis_libs, []) |
| if info is None: |
| return |
| |
| # Add include dirs |
| incl_dirs = self.get_include_dirs() |
| dict_append(info, |
| language='c', |
| define_macros=[('HAVE_CBLAS', None)], |
| include_dirs=incl_dirs) |
| self.set_info(**info) |
| |
| |
| class flame_info(system_info): |
| """ Usage of libflame for LAPACK operations |
| |
| This requires libflame to be compiled with lapack wrappers: |
| |
| ./configure --enable-lapack2flame ... |
| |
| Be aware that libflame 5.1.0 has some missing names in the shared library, so |
| if you have problems, try the static flame library. |
| """ |
| section = 'flame' |
| _lib_names = ['flame'] |
| notfounderror = FlameNotFoundError |
| |
| def check_embedded_lapack(self, info): |
| """ libflame does not necessarily have a wrapper for fortran LAPACK, we need to check """ |
| c = customized_ccompiler() |
| |
| tmpdir = tempfile.mkdtemp() |
| s = textwrap.dedent("""\ |
| void zungqr_(); |
| int main(int argc, const char *argv[]) |
| { |
| zungqr_(); |
| return 0; |
| }""") |
| src = os.path.join(tmpdir, 'source.c') |
| out = os.path.join(tmpdir, 'a.out') |
| # Add the additional "extra" arguments |
| extra_args = info.get('extra_link_args', []) |
| try: |
| with open(src, 'w') as f: |
| f.write(s) |
| obj = c.compile([src], output_dir=tmpdir) |
| try: |
| c.link_executable(obj, out, libraries=info['libraries'], |
| library_dirs=info['library_dirs'], |
| extra_postargs=extra_args) |
| return True |
| except distutils.ccompiler.LinkError: |
| return False |
| finally: |
| shutil.rmtree(tmpdir) |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| flame_libs = self.get_libs('libraries', self._lib_names) |
| |
| info = self.check_libs2(lib_dirs, flame_libs, []) |
| if info is None: |
| return |
| |
| # Add the extra flag args to info |
| extra_info = self.calc_extra_info() |
| dict_append(info, **extra_info) |
| |
| if self.check_embedded_lapack(info): |
| # check if the user has supplied all information required |
| self.set_info(**info) |
| else: |
| # Try and get the BLAS lib to see if we can get it to work |
| blas_info = get_info('blas_opt') |
| if not blas_info: |
| # since we already failed once, this ain't going to work either |
| return |
| |
| # Now we need to merge the two dictionaries |
| for key in blas_info: |
| if isinstance(blas_info[key], list): |
| info[key] = info.get(key, []) + blas_info[key] |
| elif isinstance(blas_info[key], tuple): |
| info[key] = info.get(key, ()) + blas_info[key] |
| else: |
| info[key] = info.get(key, '') + blas_info[key] |
| |
| # Now check again |
| if self.check_embedded_lapack(info): |
| self.set_info(**info) |
| |
| |
| class accelerate_info(system_info): |
| section = 'accelerate' |
| _lib_names = ['accelerate', 'veclib'] |
| notfounderror = BlasNotFoundError |
| |
| def calc_info(self): |
| # Make possible to enable/disable from config file/env var |
| libraries = os.environ.get('ACCELERATE') |
| if libraries: |
| libraries = [libraries] |
| else: |
| libraries = self.get_libs('libraries', self._lib_names) |
| libraries = [lib.strip().lower() for lib in libraries] |
| |
| if (sys.platform == 'darwin' and |
| not os.getenv('_PYTHON_HOST_PLATFORM', None)): |
| # Use the system BLAS from Accelerate or vecLib under OSX |
| args = [] |
| link_args = [] |
| if get_platform()[-4:] == 'i386' or 'intel' in get_platform() or \ |
| 'x86_64' in get_platform() or \ |
| 'i386' in platform.platform(): |
| intel = 1 |
| else: |
| intel = 0 |
| if (os.path.exists('/System/Library/Frameworks' |
| '/Accelerate.framework/') and |
| 'accelerate' in libraries): |
| if intel: |
| args.extend(['-msse3']) |
| args.extend([ |
| '-I/System/Library/Frameworks/vecLib.framework/Headers']) |
| link_args.extend(['-Wl,-framework', '-Wl,Accelerate']) |
| elif (os.path.exists('/System/Library/Frameworks' |
| '/vecLib.framework/') and |
| 'veclib' in libraries): |
| if intel: |
| args.extend(['-msse3']) |
| args.extend([ |
| '-I/System/Library/Frameworks/vecLib.framework/Headers']) |
| link_args.extend(['-Wl,-framework', '-Wl,vecLib']) |
| |
| if args: |
| self.set_info(extra_compile_args=args, |
| extra_link_args=link_args, |
| define_macros=[('NO_ATLAS_INFO', 3), |
| ('HAVE_CBLAS', None)]) |
| |
| return |
| |
| class blas_src_info(system_info): |
| # BLAS_SRC is deprecated, please do not use this! |
| # Build or install a BLAS library via your package manager or from |
| # source separately. |
| section = 'blas_src' |
| dir_env_var = 'BLAS_SRC' |
| notfounderror = BlasSrcNotFoundError |
| |
| def get_paths(self, section, key): |
| pre_dirs = system_info.get_paths(self, section, key) |
| dirs = [] |
| for d in pre_dirs: |
| dirs.extend([d] + self.combine_paths(d, ['blas'])) |
| return [d for d in dirs if os.path.isdir(d)] |
| |
| def calc_info(self): |
| src_dirs = self.get_src_dirs() |
| src_dir = '' |
| for d in src_dirs: |
| if os.path.isfile(os.path.join(d, 'daxpy.f')): |
| src_dir = d |
| break |
| if not src_dir: |
| #XXX: Get sources from netlib. May be ask first. |
| return |
| blas1 = ''' |
| caxpy csscal dnrm2 dzasum saxpy srotg zdotc ccopy cswap drot |
| dznrm2 scasum srotm zdotu cdotc dasum drotg icamax scnrm2 |
| srotmg zdrot cdotu daxpy drotm idamax scopy sscal zdscal crotg |
| dcabs1 drotmg isamax sdot sswap zrotg cscal dcopy dscal izamax |
| snrm2 zaxpy zscal csrot ddot dswap sasum srot zcopy zswap |
| scabs1 |
| ''' |
| blas2 = ''' |
| cgbmv chpmv ctrsv dsymv dtrsv sspr2 strmv zhemv ztpmv cgemv |
| chpr dgbmv dsyr lsame ssymv strsv zher ztpsv cgerc chpr2 dgemv |
| dsyr2 sgbmv ssyr xerbla zher2 ztrmv cgeru ctbmv dger dtbmv |
| sgemv ssyr2 zgbmv zhpmv ztrsv chbmv ctbsv dsbmv dtbsv sger |
| stbmv zgemv zhpr chemv ctpmv dspmv dtpmv ssbmv stbsv zgerc |
| zhpr2 cher ctpsv dspr dtpsv sspmv stpmv zgeru ztbmv cher2 |
| ctrmv dspr2 dtrmv sspr stpsv zhbmv ztbsv |
| ''' |
| blas3 = ''' |
| cgemm csymm ctrsm dsyrk sgemm strmm zhemm zsyr2k chemm csyr2k |
| dgemm dtrmm ssymm strsm zher2k zsyrk cher2k csyrk dsymm dtrsm |
| ssyr2k zherk ztrmm cherk ctrmm dsyr2k ssyrk zgemm zsymm ztrsm |
| ''' |
| sources = [os.path.join(src_dir, f + '.f') \ |
| for f in (blas1 + blas2 + blas3).split()] |
| #XXX: should we check here actual existence of source files? |
| sources = [f for f in sources if os.path.isfile(f)] |
| info = {'sources': sources, 'language': 'f77'} |
| self.set_info(**info) |
| |
| |
| class x11_info(system_info): |
| section = 'x11' |
| notfounderror = X11NotFoundError |
| _lib_names = ['X11'] |
| |
| def __init__(self): |
| system_info.__init__(self, |
| default_lib_dirs=default_x11_lib_dirs, |
| default_include_dirs=default_x11_include_dirs) |
| |
| def calc_info(self): |
| if sys.platform in ['win32']: |
| return |
| lib_dirs = self.get_lib_dirs() |
| include_dirs = self.get_include_dirs() |
| opt = self.get_option_single('x11_libs', 'libraries') |
| x11_libs = self.get_libs(opt, self._lib_names) |
| info = self.check_libs(lib_dirs, x11_libs, []) |
| if info is None: |
| return |
| inc_dir = None |
| for d in include_dirs: |
| if self.combine_paths(d, 'X11/X.h'): |
| inc_dir = d |
| break |
| if inc_dir is not None: |
| dict_append(info, include_dirs=[inc_dir]) |
| self.set_info(**info) |
| |
| |
| class _numpy_info(system_info): |
| section = 'Numeric' |
| modulename = 'Numeric' |
| notfounderror = NumericNotFoundError |
| |
| def __init__(self): |
| include_dirs = [] |
| try: |
| module = __import__(self.modulename) |
| prefix = [] |
| for name in module.__file__.split(os.sep): |
| if name == 'lib': |
| break |
| prefix.append(name) |
| |
| # Ask numpy for its own include path before attempting |
| # anything else |
| try: |
| include_dirs.append(getattr(module, 'get_include')()) |
| except AttributeError: |
| pass |
| |
| include_dirs.append(sysconfig.get_path('include')) |
| except ImportError: |
| pass |
| py_incl_dir = sysconfig.get_path('include') |
| include_dirs.append(py_incl_dir) |
| py_pincl_dir = sysconfig.get_path('platinclude') |
| if py_pincl_dir not in include_dirs: |
| include_dirs.append(py_pincl_dir) |
| for d in default_include_dirs: |
| d = os.path.join(d, os.path.basename(py_incl_dir)) |
| if d not in include_dirs: |
| include_dirs.append(d) |
| system_info.__init__(self, |
| default_lib_dirs=[], |
| default_include_dirs=include_dirs) |
| |
| def calc_info(self): |
| try: |
| module = __import__(self.modulename) |
| except ImportError: |
| return |
| info = {} |
| macros = [] |
| for v in ['__version__', 'version']: |
| vrs = getattr(module, v, None) |
| if vrs is None: |
| continue |
| macros = [(self.modulename.upper() + '_VERSION', |
| _c_string_literal(vrs)), |
| (self.modulename.upper(), None)] |
| break |
| dict_append(info, define_macros=macros) |
| include_dirs = self.get_include_dirs() |
| inc_dir = None |
| for d in include_dirs: |
| if self.combine_paths(d, |
| os.path.join(self.modulename, |
| 'arrayobject.h')): |
| inc_dir = d |
| break |
| if inc_dir is not None: |
| dict_append(info, include_dirs=[inc_dir]) |
| if info: |
| self.set_info(**info) |
| return |
| |
| |
| class numarray_info(_numpy_info): |
| section = 'numarray' |
| modulename = 'numarray' |
| |
| |
| class Numeric_info(_numpy_info): |
| section = 'Numeric' |
| modulename = 'Numeric' |
| |
| |
| class numpy_info(_numpy_info): |
| section = 'numpy' |
| modulename = 'numpy' |
| |
| |
| class numerix_info(system_info): |
| section = 'numerix' |
| |
| def calc_info(self): |
| which = None, None |
| if os.getenv("NUMERIX"): |
| which = os.getenv("NUMERIX"), "environment var" |
| # If all the above fail, default to numpy. |
| if which[0] is None: |
| which = "numpy", "defaulted" |
| try: |
| import numpy # noqa: F401 |
| which = "numpy", "defaulted" |
| except ImportError as e: |
| msg1 = str(e) |
| try: |
| import Numeric # noqa: F401 |
| which = "numeric", "defaulted" |
| except ImportError as e: |
| msg2 = str(e) |
| try: |
| import numarray # noqa: F401 |
| which = "numarray", "defaulted" |
| except ImportError as e: |
| msg3 = str(e) |
| log.info(msg1) |
| log.info(msg2) |
| log.info(msg3) |
| which = which[0].strip().lower(), which[1] |
| if which[0] not in ["numeric", "numarray", "numpy"]: |
| raise ValueError("numerix selector must be either 'Numeric' " |
| "or 'numarray' or 'numpy' but the value obtained" |
| " from the %s was '%s'." % (which[1], which[0])) |
| os.environ['NUMERIX'] = which[0] |
| self.set_info(**get_info(which[0])) |
| |
| |
| class f2py_info(system_info): |
| def calc_info(self): |
| try: |
| import numpy.f2py as f2py |
| except ImportError: |
| return |
| f2py_dir = os.path.join(os.path.dirname(f2py.__file__), 'src') |
| self.set_info(sources=[os.path.join(f2py_dir, 'fortranobject.c')], |
| include_dirs=[f2py_dir]) |
| return |
| |
| |
| class boost_python_info(system_info): |
| section = 'boost_python' |
| dir_env_var = 'BOOST' |
| |
| def get_paths(self, section, key): |
| pre_dirs = system_info.get_paths(self, section, key) |
| dirs = [] |
| for d in pre_dirs: |
| dirs.extend([d] + self.combine_paths(d, ['boost*'])) |
| return [d for d in dirs if os.path.isdir(d)] |
| |
| def calc_info(self): |
| src_dirs = self.get_src_dirs() |
| src_dir = '' |
| for d in src_dirs: |
| if os.path.isfile(os.path.join(d, 'libs', 'python', 'src', |
| 'module.cpp')): |
| src_dir = d |
| break |
| if not src_dir: |
| return |
| py_incl_dirs = [sysconfig.get_path('include')] |
| py_pincl_dir = sysconfig.get_path('platinclude') |
| if py_pincl_dir not in py_incl_dirs: |
| py_incl_dirs.append(py_pincl_dir) |
| srcs_dir = os.path.join(src_dir, 'libs', 'python', 'src') |
| bpl_srcs = glob(os.path.join(srcs_dir, '*.cpp')) |
| bpl_srcs += glob(os.path.join(srcs_dir, '*', '*.cpp')) |
| info = {'libraries': [('boost_python_src', |
| {'include_dirs': [src_dir] + py_incl_dirs, |
| 'sources':bpl_srcs} |
| )], |
| 'include_dirs': [src_dir], |
| } |
| if info: |
| self.set_info(**info) |
| return |
| |
| |
| class agg2_info(system_info): |
| section = 'agg2' |
| dir_env_var = 'AGG2' |
| |
| def get_paths(self, section, key): |
| pre_dirs = system_info.get_paths(self, section, key) |
| dirs = [] |
| for d in pre_dirs: |
| dirs.extend([d] + self.combine_paths(d, ['agg2*'])) |
| return [d for d in dirs if os.path.isdir(d)] |
| |
| def calc_info(self): |
| src_dirs = self.get_src_dirs() |
| src_dir = '' |
| for d in src_dirs: |
| if os.path.isfile(os.path.join(d, 'src', 'agg_affine_matrix.cpp')): |
| src_dir = d |
| break |
| if not src_dir: |
| return |
| if sys.platform == 'win32': |
| agg2_srcs = glob(os.path.join(src_dir, 'src', 'platform', |
| 'win32', 'agg_win32_bmp.cpp')) |
| else: |
| agg2_srcs = glob(os.path.join(src_dir, 'src', '*.cpp')) |
| agg2_srcs += [os.path.join(src_dir, 'src', 'platform', |
| 'X11', |
| 'agg_platform_support.cpp')] |
| |
| info = {'libraries': |
| [('agg2_src', |
| {'sources': agg2_srcs, |
| 'include_dirs': [os.path.join(src_dir, 'include')], |
| } |
| )], |
| 'include_dirs': [os.path.join(src_dir, 'include')], |
| } |
| if info: |
| self.set_info(**info) |
| return |
| |
| |
| class _pkg_config_info(system_info): |
| section = None |
| config_env_var = 'PKG_CONFIG' |
| default_config_exe = 'pkg-config' |
| append_config_exe = '' |
| version_macro_name = None |
| release_macro_name = None |
| version_flag = '--modversion' |
| cflags_flag = '--cflags' |
| |
| def get_config_exe(self): |
| if self.config_env_var in os.environ: |
| return os.environ[self.config_env_var] |
| return self.default_config_exe |
| |
| def get_config_output(self, config_exe, option): |
| cmd = config_exe + ' ' + self.append_config_exe + ' ' + option |
| try: |
| o = subprocess.check_output(cmd) |
| except (OSError, subprocess.CalledProcessError): |
| pass |
| else: |
| o = filepath_from_subprocess_output(o) |
| return o |
| |
| def calc_info(self): |
| config_exe = find_executable(self.get_config_exe()) |
| if not config_exe: |
| log.warn('File not found: %s. Cannot determine %s info.' \ |
| % (config_exe, self.section)) |
| return |
| info = {} |
| macros = [] |
| libraries = [] |
| library_dirs = [] |
| include_dirs = [] |
| extra_link_args = [] |
| extra_compile_args = [] |
| version = self.get_config_output(config_exe, self.version_flag) |
| if version: |
| macros.append((self.__class__.__name__.split('.')[-1].upper(), |
| _c_string_literal(version))) |
| if self.version_macro_name: |
| macros.append((self.version_macro_name + '_%s' |
| % (version.replace('.', '_')), None)) |
| if self.release_macro_name: |
| release = self.get_config_output(config_exe, '--release') |
| if release: |
| macros.append((self.release_macro_name + '_%s' |
| % (release.replace('.', '_')), None)) |
| opts = self.get_config_output(config_exe, '--libs') |
| if opts: |
| for opt in opts.split(): |
| if opt[:2] == '-l': |
| libraries.append(opt[2:]) |
| elif opt[:2] == '-L': |
| library_dirs.append(opt[2:]) |
| else: |
| extra_link_args.append(opt) |
| opts = self.get_config_output(config_exe, self.cflags_flag) |
| if opts: |
| for opt in opts.split(): |
| if opt[:2] == '-I': |
| include_dirs.append(opt[2:]) |
| elif opt[:2] == '-D': |
| if '=' in opt: |
| n, v = opt[2:].split('=') |
| macros.append((n, v)) |
| else: |
| macros.append((opt[2:], None)) |
| else: |
| extra_compile_args.append(opt) |
| if macros: |
| dict_append(info, define_macros=macros) |
| if libraries: |
| dict_append(info, libraries=libraries) |
| if library_dirs: |
| dict_append(info, library_dirs=library_dirs) |
| if include_dirs: |
| dict_append(info, include_dirs=include_dirs) |
| if extra_link_args: |
| dict_append(info, extra_link_args=extra_link_args) |
| if extra_compile_args: |
| dict_append(info, extra_compile_args=extra_compile_args) |
| if info: |
| self.set_info(**info) |
| return |
| |
| |
| class wx_info(_pkg_config_info): |
| section = 'wx' |
| config_env_var = 'WX_CONFIG' |
| default_config_exe = 'wx-config' |
| append_config_exe = '' |
| version_macro_name = 'WX_VERSION' |
| release_macro_name = 'WX_RELEASE' |
| version_flag = '--version' |
| cflags_flag = '--cxxflags' |
| |
| |
| class gdk_pixbuf_xlib_2_info(_pkg_config_info): |
| section = 'gdk_pixbuf_xlib_2' |
| append_config_exe = 'gdk-pixbuf-xlib-2.0' |
| version_macro_name = 'GDK_PIXBUF_XLIB_VERSION' |
| |
| |
| class gdk_pixbuf_2_info(_pkg_config_info): |
| section = 'gdk_pixbuf_2' |
| append_config_exe = 'gdk-pixbuf-2.0' |
| version_macro_name = 'GDK_PIXBUF_VERSION' |
| |
| |
| class gdk_x11_2_info(_pkg_config_info): |
| section = 'gdk_x11_2' |
| append_config_exe = 'gdk-x11-2.0' |
| version_macro_name = 'GDK_X11_VERSION' |
| |
| |
| class gdk_2_info(_pkg_config_info): |
| section = 'gdk_2' |
| append_config_exe = 'gdk-2.0' |
| version_macro_name = 'GDK_VERSION' |
| |
| |
| class gdk_info(_pkg_config_info): |
| section = 'gdk' |
| append_config_exe = 'gdk' |
| version_macro_name = 'GDK_VERSION' |
| |
| |
| class gtkp_x11_2_info(_pkg_config_info): |
| section = 'gtkp_x11_2' |
| append_config_exe = 'gtk+-x11-2.0' |
| version_macro_name = 'GTK_X11_VERSION' |
| |
| |
| class gtkp_2_info(_pkg_config_info): |
| section = 'gtkp_2' |
| append_config_exe = 'gtk+-2.0' |
| version_macro_name = 'GTK_VERSION' |
| |
| |
| class xft_info(_pkg_config_info): |
| section = 'xft' |
| append_config_exe = 'xft' |
| version_macro_name = 'XFT_VERSION' |
| |
| |
| class freetype2_info(_pkg_config_info): |
| section = 'freetype2' |
| append_config_exe = 'freetype2' |
| version_macro_name = 'FREETYPE2_VERSION' |
| |
| |
| class amd_info(system_info): |
| section = 'amd' |
| dir_env_var = 'AMD' |
| _lib_names = ['amd'] |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| |
| opt = self.get_option_single('amd_libs', 'libraries') |
| amd_libs = self.get_libs(opt, self._lib_names) |
| info = self.check_libs(lib_dirs, amd_libs, []) |
| if info is None: |
| return |
| |
| include_dirs = self.get_include_dirs() |
| |
| inc_dir = None |
| for d in include_dirs: |
| p = self.combine_paths(d, 'amd.h') |
| if p: |
| inc_dir = os.path.dirname(p[0]) |
| break |
| if inc_dir is not None: |
| dict_append(info, include_dirs=[inc_dir], |
| define_macros=[('SCIPY_AMD_H', None)], |
| swig_opts=['-I' + inc_dir]) |
| |
| self.set_info(**info) |
| return |
| |
| |
| class umfpack_info(system_info): |
| section = 'umfpack' |
| dir_env_var = 'UMFPACK' |
| notfounderror = UmfpackNotFoundError |
| _lib_names = ['umfpack'] |
| |
| def calc_info(self): |
| lib_dirs = self.get_lib_dirs() |
| |
| opt = self.get_option_single('umfpack_libs', 'libraries') |
| umfpack_libs = self.get_libs(opt, self._lib_names) |
| info = self.check_libs(lib_dirs, umfpack_libs, []) |
| if info is None: |
| return |
| |
| include_dirs = self.get_include_dirs() |
| |
| inc_dir = None |
| for d in include_dirs: |
| p = self.combine_paths(d, ['', 'umfpack'], 'umfpack.h') |
| if p: |
| inc_dir = os.path.dirname(p[0]) |
| break |
| if inc_dir is not None: |
| dict_append(info, include_dirs=[inc_dir], |
| define_macros=[('SCIPY_UMFPACK_H', None)], |
| swig_opts=['-I' + inc_dir]) |
| |
| dict_append(info, **get_info('amd')) |
| |
| self.set_info(**info) |
| return |
| |
| |
| def combine_paths(*args, **kws): |
| """ Return a list of existing paths composed by all combinations of |
| items from arguments. |
| """ |
| r = [] |
| for a in args: |
| if not a: |
| continue |
| if is_string(a): |
| a = [a] |
| r.append(a) |
| args = r |
| if not args: |
| return [] |
| if len(args) == 1: |
| result = reduce(lambda a, b: a + b, map(glob, args[0]), []) |
| elif len(args) == 2: |
| result = [] |
| for a0 in args[0]: |
| for a1 in args[1]: |
| result.extend(glob(os.path.join(a0, a1))) |
| else: |
| result = combine_paths(*(combine_paths(args[0], args[1]) + args[2:])) |
| log.debug('(paths: %s)', ','.join(result)) |
| return result |
| |
| language_map = {'c': 0, 'c++': 1, 'f77': 2, 'f90': 3} |
| inv_language_map = {0: 'c', 1: 'c++', 2: 'f77', 3: 'f90'} |
| |
| |
| def dict_append(d, **kws): |
| languages = [] |
| for k, v in kws.items(): |
| if k == 'language': |
| languages.append(v) |
| continue |
| if k in d: |
| if k in ['library_dirs', 'include_dirs', |
| 'extra_compile_args', 'extra_link_args', |
| 'runtime_library_dirs', 'define_macros']: |
| [d[k].append(vv) for vv in v if vv not in d[k]] |
| else: |
| d[k].extend(v) |
| else: |
| d[k] = v |
| if languages: |
| l = inv_language_map[max([language_map.get(l, 0) for l in languages])] |
| d['language'] = l |
| return |
| |
| |
| def parseCmdLine(argv=(None,)): |
| import optparse |
| parser = optparse.OptionParser("usage: %prog [-v] [info objs]") |
| parser.add_option('-v', '--verbose', action='store_true', dest='verbose', |
| default=False, |
| help='be verbose and print more messages') |
| |
| opts, args = parser.parse_args(args=argv[1:]) |
| return opts, args |
| |
| |
| def show_all(argv=None): |
| import inspect |
| if argv is None: |
| argv = sys.argv |
| opts, args = parseCmdLine(argv) |
| if opts.verbose: |
| log.set_threshold(log.DEBUG) |
| else: |
| log.set_threshold(log.INFO) |
| show_only = [] |
| for n in args: |
| if n[-5:] != '_info': |
| n = n + '_info' |
| show_only.append(n) |
| show_all = not show_only |
| _gdict_ = globals().copy() |
| for name, c in _gdict_.items(): |
| if not inspect.isclass(c): |
| continue |
| if not issubclass(c, system_info) or c is system_info: |
| continue |
| if not show_all: |
| if name not in show_only: |
| continue |
| del show_only[show_only.index(name)] |
| conf = c() |
| conf.verbosity = 2 |
| # we don't need the result, but we want |
| # the side effect of printing diagnostics |
| conf.get_info() |
| if show_only: |
| log.info('Info classes not defined: %s', ','.join(show_only)) |
| |
| if __name__ == "__main__": |
| show_all() |