1#!/usr/bin/env python3 2""" 3This file defines a set of system_info classes for getting 4information about various resources (libraries, library directories, 5include directories, etc.) in the system. Usage: 6 info_dict = get_info(<name>) 7 where <name> is a string 'atlas','x11','fftw','lapack','blas', 8 'lapack_src', 'blas_src', etc. For a complete list of allowed names, 9 see the definition of get_info() function below. 10 11 Returned info_dict is a dictionary which is compatible with 12 distutils.setup keyword arguments. If info_dict == {}, then the 13 asked resource is not available (system_info could not find it). 14 15 Several *_info classes specify an environment variable to specify 16 the locations of software. When setting the corresponding environment 17 variable to 'None' then the software will be ignored, even when it 18 is available in system. 19 20Global parameters: 21 system_info.search_static_first - search static libraries (.a) 22 in precedence to shared ones (.so, .sl) if enabled. 23 system_info.verbosity - output the results to stdout if enabled. 24 25The file 'site.cfg' is looked for in 26 271) Directory of main setup.py file being run. 282) Home directory of user running the setup.py file as ~/.numpy-site.cfg 293) System wide directory (location of this file...) 30 31The first one found is used to get system configuration options The 32format is that used by ConfigParser (i.e., Windows .INI style). The 33section ALL is not intended for general use. 34 35Appropriate defaults are used if nothing is specified. 36 37The order of finding the locations of resources is the following: 38 1. environment variable 39 2. section in site.cfg 40 3. DEFAULT section in site.cfg 41 4. System default search paths (see ``default_*`` variables below). 42Only the first complete match is returned. 43 44Currently, the following classes are available, along with their section names: 45 46 Numeric_info:Numeric 47 _numpy_info:Numeric 48 _pkg_config_info:None 49 accelerate_info:accelerate 50 agg2_info:agg2 51 amd_info:amd 52 atlas_3_10_blas_info:atlas 53 atlas_3_10_blas_threads_info:atlas 54 atlas_3_10_info:atlas 55 atlas_3_10_threads_info:atlas 56 atlas_blas_info:atlas 57 atlas_blas_threads_info:atlas 58 atlas_info:atlas 59 atlas_threads_info:atlas 60 blas64__opt_info:ALL # usage recommended (general ILP64 BLAS, 64_ symbol suffix) 61 blas_ilp64_opt_info:ALL # usage recommended (general ILP64 BLAS) 62 blas_ilp64_plain_opt_info:ALL # usage recommended (general ILP64 BLAS, no symbol suffix) 63 blas_info:blas 64 blas_mkl_info:mkl 65 blas_opt_info:ALL # usage recommended 66 blas_src_info:blas_src 67 blis_info:blis 68 boost_python_info:boost_python 69 dfftw_info:fftw 70 dfftw_threads_info:fftw 71 djbfft_info:djbfft 72 f2py_info:ALL 73 fft_opt_info:ALL 74 fftw2_info:fftw 75 fftw3_info:fftw3 76 fftw_info:fftw 77 fftw_threads_info:fftw 78 flame_info:flame 79 freetype2_info:freetype2 80 gdk_2_info:gdk_2 81 gdk_info:gdk 82 gdk_pixbuf_2_info:gdk_pixbuf_2 83 gdk_pixbuf_xlib_2_info:gdk_pixbuf_xlib_2 84 gdk_x11_2_info:gdk_x11_2 85 gtkp_2_info:gtkp_2 86 gtkp_x11_2_info:gtkp_x11_2 87 lapack64__opt_info:ALL # usage recommended (general ILP64 LAPACK, 64_ symbol suffix) 88 lapack_atlas_3_10_info:atlas 89 lapack_atlas_3_10_threads_info:atlas 90 lapack_atlas_info:atlas 91 lapack_atlas_threads_info:atlas 92 lapack_ilp64_opt_info:ALL # usage recommended (general ILP64 LAPACK) 93 lapack_ilp64_plain_opt_info:ALL # usage recommended (general ILP64 LAPACK, no symbol suffix) 94 lapack_info:lapack 95 lapack_mkl_info:mkl 96 lapack_opt_info:ALL # usage recommended 97 lapack_src_info:lapack_src 98 mkl_info:mkl 99 numarray_info:numarray 100 numerix_info:numerix 101 numpy_info:numpy 102 openblas64__info:openblas64_ 103 openblas64__lapack_info:openblas64_ 104 openblas_clapack_info:openblas 105 openblas_ilp64_info:openblas_ilp64 106 openblas_ilp64_lapack_info:openblas_ilp64 107 openblas_info:openblas 108 openblas_lapack_info:openblas 109 sfftw_info:fftw 110 sfftw_threads_info:fftw 111 system_info:ALL 112 umfpack_info:umfpack 113 wx_info:wx 114 x11_info:x11 115 xft_info:xft 116 117Example: 118---------- 119[DEFAULT] 120# default section 121library_dirs = /usr/lib:/usr/local/lib:/opt/lib 122include_dirs = /usr/include:/usr/local/include:/opt/include 123src_dirs = /usr/local/src:/opt/src 124# search static libraries (.a) in preference to shared ones (.so) 125search_static_first = 0 126 127[fftw] 128libraries = rfftw, fftw 129 130[atlas] 131library_dirs = /usr/lib/3dnow:/usr/lib/3dnow/atlas 132# for overriding the names of the atlas libraries 133libraries = lapack, f77blas, cblas, atlas 134 135[x11] 136library_dirs = /usr/X11R6/lib 137include_dirs = /usr/X11R6/include 138---------- 139 140Note that the ``libraries`` key is the default setting for libraries. 141 142Authors: 143 Pearu Peterson <pearu@cens.ioc.ee>, February 2002 144 David M. Cooke <cookedm@physics.mcmaster.ca>, April 2002 145 146Copyright 2002 Pearu Peterson all rights reserved, 147Pearu Peterson <pearu@cens.ioc.ee> 148Permission to use, modify, and distribute this software is given under the 149terms of the NumPy (BSD style) license. See LICENSE.txt that came with 150this distribution for specifics. 151 152NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. 153 154""" 155import sys 156import os 157import re 158import copy 159import warnings 160import subprocess 161import textwrap 162 163from glob import glob 164from functools import reduce 165from configparser import NoOptionError 166from configparser import RawConfigParser as ConfigParser 167# It seems that some people are importing ConfigParser from here so is 168# good to keep its class name. Use of RawConfigParser is needed in 169# order to be able to load path names with percent in them, like 170# `feature%2Fcool` which is common on git flow branch names. 171 172from distutils.errors import DistutilsError 173from distutils.dist import Distribution 174import sysconfig 175from numpy.distutils import log 176from distutils.util import get_platform 177 178from numpy.distutils.exec_command import ( 179 find_executable, filepath_from_subprocess_output, 180 ) 181from numpy.distutils.misc_util import (is_sequence, is_string, 182 get_shared_lib_extension) 183from numpy.distutils.command.config import config as cmd_config 184from numpy.distutils import customized_ccompiler as _customized_ccompiler 185from numpy.distutils import _shell_utils 186import distutils.ccompiler 187import tempfile 188import shutil 189 190__all__ = ['system_info'] 191 192# Determine number of bits 193import platform 194_bits = {'32bit': 32, '64bit': 64} 195platform_bits = _bits[platform.architecture()[0]] 196 197 198global_compiler = None 199 200def customized_ccompiler(): 201 global global_compiler 202 if not global_compiler: 203 global_compiler = _customized_ccompiler() 204 return global_compiler 205 206 207def _c_string_literal(s): 208 """ 209 Convert a python string into a literal suitable for inclusion into C code 210 """ 211 # only these three characters are forbidden in C strings 212 if s is None: 213 return '"None"' 214 s = s.replace('\\', r'\\') 215 s = s.replace('"', r'\"') 216 s = s.replace('\n', r'\n') 217 return '"{}"'.format(s) 218 219 220def libpaths(paths, bits): 221 """Return a list of library paths valid on 32 or 64 bit systems. 222 223 Inputs: 224 paths : sequence 225 A sequence of strings (typically paths) 226 bits : int 227 An integer, the only valid values are 32 or 64. A ValueError exception 228 is raised otherwise. 229 230 Examples: 231 232 Consider a list of directories 233 >>> paths = ['/usr/X11R6/lib','/usr/X11/lib','/usr/lib'] 234 235 For a 32-bit platform, this is already valid: 236 >>> np.distutils.system_info.libpaths(paths,32) 237 ['/usr/X11R6/lib', '/usr/X11/lib', '/usr/lib'] 238 239 On 64 bits, we prepend the '64' postfix 240 >>> np.distutils.system_info.libpaths(paths,64) 241 ['/usr/X11R6/lib64', '/usr/X11R6/lib', '/usr/X11/lib64', '/usr/X11/lib', 242 '/usr/lib64', '/usr/lib'] 243 """ 244 if bits not in (32, 64): 245 raise ValueError("Invalid bit size in libpaths: 32 or 64 only") 246 247 # Handle 32bit case 248 if bits == 32: 249 return paths 250 251 # Handle 64bit case 252 out = [] 253 for p in paths: 254 out.extend([p + '64', p]) 255 256 return out 257 258 259if sys.platform == 'win32': 260 default_lib_dirs = ['C:\\', 261 os.path.join(sysconfig.get_config_var('exec_prefix'), 262 'libs')] 263 default_runtime_dirs = [] 264 default_include_dirs = [] 265 default_src_dirs = ['.'] 266 default_x11_lib_dirs = [] 267 default_x11_include_dirs = [] 268 _include_dirs = [ 269 'include', 270 'include/suitesparse', 271 ] 272 _lib_dirs = [ 273 'lib', 274 ] 275 276 _include_dirs = [d.replace('/', os.sep) for d in _include_dirs] 277 _lib_dirs = [d.replace('/', os.sep) for d in _lib_dirs] 278 def add_system_root(library_root): 279 """Add a package manager root to the include directories""" 280 global default_lib_dirs 281 global default_include_dirs 282 283 library_root = os.path.normpath(library_root) 284 285 default_lib_dirs.extend( 286 os.path.join(library_root, d) for d in _lib_dirs) 287 default_include_dirs.extend( 288 os.path.join(library_root, d) for d in _include_dirs) 289 290 # VCpkg is the de-facto package manager on windows for C/C++ 291 # libraries. If it is on the PATH, then we append its paths here. 292 vcpkg = shutil.which('vcpkg') 293 if vcpkg: 294 vcpkg_dir = os.path.dirname(vcpkg) 295 if platform.architecture()[0] == '32bit': 296 specifier = 'x86' 297 else: 298 specifier = 'x64' 299 300 vcpkg_installed = os.path.join(vcpkg_dir, 'installed') 301 for vcpkg_root in [ 302 os.path.join(vcpkg_installed, specifier + '-windows'), 303 os.path.join(vcpkg_installed, specifier + '-windows-static'), 304 ]: 305 add_system_root(vcpkg_root) 306 307 # Conda is another popular package manager that provides libraries 308 conda = shutil.which('conda') 309 if conda: 310 conda_dir = os.path.dirname(conda) 311 add_system_root(os.path.join(conda_dir, '..', 'Library')) 312 add_system_root(os.path.join(conda_dir, 'Library')) 313 314else: 315 default_lib_dirs = libpaths(['/usr/local/lib', '/opt/lib', '/usr/lib', 316 '/opt/local/lib', '/sw/lib'], platform_bits) 317 default_runtime_dirs = [] 318 default_include_dirs = ['/usr/local/include', 319 '/opt/include', '/usr/include', 320 # path of umfpack under macports 321 '/opt/local/include/ufsparse', 322 '/opt/local/include', '/sw/include', 323 '/usr/include/suitesparse'] 324 default_src_dirs = ['.', '/usr/local/src', '/opt/src', '/sw/src'] 325 326 default_x11_lib_dirs = libpaths(['/usr/X11R6/lib', '/usr/X11/lib', 327 '/usr/lib'], platform_bits) 328 default_x11_include_dirs = ['/usr/X11R6/include', '/usr/X11/include', 329 '/usr/include'] 330 331 if os.path.exists('/usr/lib/X11'): 332 globbed_x11_dir = glob('/usr/lib/*/libX11.so') 333 if globbed_x11_dir: 334 x11_so_dir = os.path.split(globbed_x11_dir[0])[0] 335 default_x11_lib_dirs.extend([x11_so_dir, '/usr/lib/X11']) 336 default_x11_include_dirs.extend(['/usr/lib/X11/include', 337 '/usr/include/X11']) 338 339 with open(os.devnull, 'w') as tmp: 340 try: 341 p = subprocess.Popen(["gcc", "-print-multiarch"], stdout=subprocess.PIPE, 342 stderr=tmp) 343 except (OSError, DistutilsError): 344 # OSError if gcc is not installed, or SandboxViolation (DistutilsError 345 # subclass) if an old setuptools bug is triggered (see gh-3160). 346 pass 347 else: 348 triplet = str(p.communicate()[0].decode().strip()) 349 if p.returncode == 0: 350 # gcc supports the "-print-multiarch" option 351 default_x11_lib_dirs += [os.path.join("/usr/lib/", triplet)] 352 default_lib_dirs += [os.path.join("/usr/lib/", triplet)] 353 354 355if os.path.join(sys.prefix, 'lib') not in default_lib_dirs: 356 default_lib_dirs.insert(0, os.path.join(sys.prefix, 'lib')) 357 default_include_dirs.append(os.path.join(sys.prefix, 'include')) 358 default_src_dirs.append(os.path.join(sys.prefix, 'src')) 359 360default_lib_dirs = [_m for _m in default_lib_dirs if os.path.isdir(_m)] 361default_runtime_dirs = [_m for _m in default_runtime_dirs if os.path.isdir(_m)] 362default_include_dirs = [_m for _m in default_include_dirs if os.path.isdir(_m)] 363default_src_dirs = [_m for _m in default_src_dirs if os.path.isdir(_m)] 364 365so_ext = get_shared_lib_extension() 366 367 368def is_symlink_to_accelerate(filename): 369 accelpath = '/System/Library/Frameworks/Accelerate.framework' 370 return (sys.platform == 'darwin' and os.path.islink(filename) and 371 os.path.realpath(filename).startswith(accelpath)) 372 373 374_accel_msg = ( 375 'Found {filename}, but that file is a symbolic link to the ' 376 'MacOS Accelerate framework, which is not supported by NumPy. ' 377 'You must configure the build to use a different optimized library, ' 378 'or disable the use of optimized BLAS and LAPACK by setting the ' 379 'environment variables NPY_BLAS_ORDER="" and NPY_LAPACK_ORDER="" ' 380 'before building NumPy.' 381) 382 383 384def get_standard_file(fname): 385 """Returns a list of files named 'fname' from 386 1) System-wide directory (directory-location of this module) 387 2) Users HOME directory (os.environ['HOME']) 388 3) Local directory 389 """ 390 # System-wide file 391 filenames = [] 392 try: 393 f = __file__ 394 except NameError: 395 f = sys.argv[0] 396 else: 397 sysfile = os.path.join(os.path.split(os.path.abspath(f))[0], 398 fname) 399 if os.path.isfile(sysfile): 400 filenames.append(sysfile) 401 402 # Home directory 403 # And look for the user config file 404 try: 405 f = os.path.expanduser('~') 406 except KeyError: 407 pass 408 else: 409 user_file = os.path.join(f, fname) 410 if os.path.isfile(user_file): 411 filenames.append(user_file) 412 413 # Local file 414 if os.path.isfile(fname): 415 filenames.append(os.path.abspath(fname)) 416 417 return filenames 418 419 420def _parse_env_order(base_order, env): 421 """ Parse an environment variable `env` by splitting with "," and only returning elements from `base_order` 422 423 This method will sequence the environment variable and check for their invidual elements in `base_order`. 424 425 The items in the environment variable may be negated via '^item' or '!itema,itemb'. 426 It must start with ^/! to negate all options. 427 428 Raises 429 ------ 430 ValueError: for mixed negated and non-negated orders or multiple negated orders 431 432 Parameters 433 ---------- 434 base_order : list of str 435 the base list of orders 436 env : str 437 the environment variable to be parsed, if none is found, `base_order` is returned 438 439 Returns 440 ------- 441 allow_order : list of str 442 allowed orders in lower-case 443 unknown_order : list of str 444 for values not overlapping with `base_order` 445 """ 446 order_str = os.environ.get(env, None) 447 448 # ensure all base-orders are lower-case (for easier comparison) 449 base_order = [order.lower() for order in base_order] 450 if order_str is None: 451 return base_order, [] 452 453 neg = order_str.startswith('^') or order_str.startswith('!') 454 # Check format 455 order_str_l = list(order_str) 456 sum_neg = order_str_l.count('^') + order_str_l.count('!') 457 if neg: 458 if sum_neg > 1: 459 raise ValueError(f"Environment variable '{env}' may only contain a single (prefixed) negation: {order_str}") 460 # remove prefix 461 order_str = order_str[1:] 462 elif sum_neg > 0: 463 raise ValueError(f"Environment variable '{env}' may not mix negated an non-negated items: {order_str}") 464 465 # Split and lower case 466 orders = order_str.lower().split(',') 467 468 # to inform callee about non-overlapping elements 469 unknown_order = [] 470 471 # if negated, we have to remove from the order 472 if neg: 473 allow_order = base_order.copy() 474 475 for order in orders: 476 if not order: 477 continue 478 479 if order not in base_order: 480 unknown_order.append(order) 481 continue 482 483 if order in allow_order: 484 allow_order.remove(order) 485 486 else: 487 allow_order = [] 488 489 for order in orders: 490 if not order: 491 continue 492 493 if order not in base_order: 494 unknown_order.append(order) 495 continue 496 497 if order not in allow_order: 498 allow_order.append(order) 499 500 return allow_order, unknown_order 501 502 503def get_info(name, notfound_action=0): 504 """ 505 notfound_action: 506 0 - do nothing 507 1 - display warning message 508 2 - raise error 509 """ 510 cl = {'atlas': atlas_info, # use lapack_opt or blas_opt instead 511 'atlas_threads': atlas_threads_info, # ditto 512 'atlas_blas': atlas_blas_info, 513 'atlas_blas_threads': atlas_blas_threads_info, 514 'lapack_atlas': lapack_atlas_info, # use lapack_opt instead 515 'lapack_atlas_threads': lapack_atlas_threads_info, # ditto 516 'atlas_3_10': atlas_3_10_info, # use lapack_opt or blas_opt instead 517 'atlas_3_10_threads': atlas_3_10_threads_info, # ditto 518 'atlas_3_10_blas': atlas_3_10_blas_info, 519 'atlas_3_10_blas_threads': atlas_3_10_blas_threads_info, 520 'lapack_atlas_3_10': lapack_atlas_3_10_info, # use lapack_opt instead 521 'lapack_atlas_3_10_threads': lapack_atlas_3_10_threads_info, # ditto 522 'flame': flame_info, # use lapack_opt instead 523 'mkl': mkl_info, 524 # openblas which may or may not have embedded lapack 525 'openblas': openblas_info, # use blas_opt instead 526 # openblas with embedded lapack 527 'openblas_lapack': openblas_lapack_info, # use blas_opt instead 528 'openblas_clapack': openblas_clapack_info, # use blas_opt instead 529 'blis': blis_info, # use blas_opt instead 530 'lapack_mkl': lapack_mkl_info, # use lapack_opt instead 531 'blas_mkl': blas_mkl_info, # use blas_opt instead 532 'openblas64_': openblas64__info, 533 'openblas64__lapack': openblas64__lapack_info, 534 'openblas_ilp64': openblas_ilp64_info, 535 'openblas_ilp64_lapack': openblas_ilp64_lapack_info, 536 'x11': x11_info, 537 'fft_opt': fft_opt_info, 538 'fftw': fftw_info, 539 'fftw2': fftw2_info, 540 'fftw3': fftw3_info, 541 'dfftw': dfftw_info, 542 'sfftw': sfftw_info, 543 'fftw_threads': fftw_threads_info, 544 'dfftw_threads': dfftw_threads_info, 545 'sfftw_threads': sfftw_threads_info, 546 'djbfft': djbfft_info, 547 'blas': blas_info, # use blas_opt instead 548 'lapack': lapack_info, # use lapack_opt instead 549 'lapack_src': lapack_src_info, 550 'blas_src': blas_src_info, 551 'numpy': numpy_info, 552 'f2py': f2py_info, 553 'Numeric': Numeric_info, 554 'numeric': Numeric_info, 555 'numarray': numarray_info, 556 'numerix': numerix_info, 557 'lapack_opt': lapack_opt_info, 558 'lapack_ilp64_opt': lapack_ilp64_opt_info, 559 'lapack_ilp64_plain_opt': lapack_ilp64_plain_opt_info, 560 'lapack64__opt': lapack64__opt_info, 561 'blas_opt': blas_opt_info, 562 'blas_ilp64_opt': blas_ilp64_opt_info, 563 'blas_ilp64_plain_opt': blas_ilp64_plain_opt_info, 564 'blas64__opt': blas64__opt_info, 565 'boost_python': boost_python_info, 566 'agg2': agg2_info, 567 'wx': wx_info, 568 'gdk_pixbuf_xlib_2': gdk_pixbuf_xlib_2_info, 569 'gdk-pixbuf-xlib-2.0': gdk_pixbuf_xlib_2_info, 570 'gdk_pixbuf_2': gdk_pixbuf_2_info, 571 'gdk-pixbuf-2.0': gdk_pixbuf_2_info, 572 'gdk': gdk_info, 573 'gdk_2': gdk_2_info, 574 'gdk-2.0': gdk_2_info, 575 'gdk_x11_2': gdk_x11_2_info, 576 'gdk-x11-2.0': gdk_x11_2_info, 577 'gtkp_x11_2': gtkp_x11_2_info, 578 'gtk+-x11-2.0': gtkp_x11_2_info, 579 'gtkp_2': gtkp_2_info, 580 'gtk+-2.0': gtkp_2_info, 581 'xft': xft_info, 582 'freetype2': freetype2_info, 583 'umfpack': umfpack_info, 584 'amd': amd_info, 585 }.get(name.lower(), system_info) 586 return cl().get_info(notfound_action) 587 588 589class NotFoundError(DistutilsError): 590 """Some third-party program or library is not found.""" 591 592 593class AliasedOptionError(DistutilsError): 594 """ 595 Aliases entries in config files should not be existing. 596 In section '{section}' we found multiple appearances of options {options}.""" 597 598 599class AtlasNotFoundError(NotFoundError): 600 """ 601 Atlas (http://github.com/math-atlas/math-atlas) libraries not found. 602 Directories to search for the libraries can be specified in the 603 numpy/distutils/site.cfg file (section [atlas]) or by setting 604 the ATLAS environment variable.""" 605 606 607class FlameNotFoundError(NotFoundError): 608 """ 609 FLAME (http://www.cs.utexas.edu/~flame/web/) libraries not found. 610 Directories to search for the libraries can be specified in the 611 numpy/distutils/site.cfg file (section [flame]).""" 612 613 614class LapackNotFoundError(NotFoundError): 615 """ 616 Lapack (http://www.netlib.org/lapack/) libraries not found. 617 Directories to search for the libraries can be specified in the 618 numpy/distutils/site.cfg file (section [lapack]) or by setting 619 the LAPACK environment variable.""" 620 621 622class LapackSrcNotFoundError(LapackNotFoundError): 623 """ 624 Lapack (http://www.netlib.org/lapack/) sources not found. 625 Directories to search for the sources can be specified in the 626 numpy/distutils/site.cfg file (section [lapack_src]) or by setting 627 the LAPACK_SRC environment variable.""" 628 629 630class LapackILP64NotFoundError(NotFoundError): 631 """ 632 64-bit Lapack libraries not found. 633 Known libraries in numpy/distutils/site.cfg file are: 634 openblas64_, openblas_ilp64 635 """ 636 637class BlasOptNotFoundError(NotFoundError): 638 """ 639 Optimized (vendor) Blas libraries are not found. 640 Falls back to netlib Blas library which has worse performance. 641 A better performance should be easily gained by switching 642 Blas library.""" 643 644class BlasNotFoundError(NotFoundError): 645 """ 646 Blas (http://www.netlib.org/blas/) libraries not found. 647 Directories to search for the libraries can be specified in the 648 numpy/distutils/site.cfg file (section [blas]) or by setting 649 the BLAS environment variable.""" 650 651class BlasILP64NotFoundError(NotFoundError): 652 """ 653 64-bit Blas libraries not found. 654 Known libraries in numpy/distutils/site.cfg file are: 655 openblas64_, openblas_ilp64 656 """ 657 658class BlasSrcNotFoundError(BlasNotFoundError): 659 """ 660 Blas (http://www.netlib.org/blas/) sources not found. 661 Directories to search for the sources can be specified in the 662 numpy/distutils/site.cfg file (section [blas_src]) or by setting 663 the BLAS_SRC environment variable.""" 664 665 666class FFTWNotFoundError(NotFoundError): 667 """ 668 FFTW (http://www.fftw.org/) libraries not found. 669 Directories to search for the libraries can be specified in the 670 numpy/distutils/site.cfg file (section [fftw]) or by setting 671 the FFTW environment variable.""" 672 673 674class DJBFFTNotFoundError(NotFoundError): 675 """ 676 DJBFFT (https://cr.yp.to/djbfft.html) libraries not found. 677 Directories to search for the libraries can be specified in the 678 numpy/distutils/site.cfg file (section [djbfft]) or by setting 679 the DJBFFT environment variable.""" 680 681 682class NumericNotFoundError(NotFoundError): 683 """ 684 Numeric (https://www.numpy.org/) module not found. 685 Get it from above location, install it, and retry setup.py.""" 686 687 688class X11NotFoundError(NotFoundError): 689 """X11 libraries not found.""" 690 691 692class UmfpackNotFoundError(NotFoundError): 693 """ 694 UMFPACK sparse solver (https://www.cise.ufl.edu/research/sparse/umfpack/) 695 not found. Directories to search for the libraries can be specified in the 696 numpy/distutils/site.cfg file (section [umfpack]) or by setting 697 the UMFPACK environment variable.""" 698 699 700class system_info: 701 702 """ get_info() is the only public method. Don't use others. 703 """ 704 dir_env_var = None 705 # XXX: search_static_first is disabled by default, may disappear in 706 # future unless it is proved to be useful. 707 search_static_first = 0 708 # The base-class section name is a random word "ALL" and is not really 709 # intended for general use. It cannot be None nor can it be DEFAULT as 710 # these break the ConfigParser. See gh-15338 711 section = 'ALL' 712 saved_results = {} 713 714 notfounderror = NotFoundError 715 716 def __init__(self, 717 default_lib_dirs=default_lib_dirs, 718 default_include_dirs=default_include_dirs, 719 ): 720 self.__class__.info = {} 721 self.local_prefixes = [] 722 defaults = {'library_dirs': os.pathsep.join(default_lib_dirs), 723 'include_dirs': os.pathsep.join(default_include_dirs), 724 'runtime_library_dirs': os.pathsep.join(default_runtime_dirs), 725 'rpath': '', 726 'src_dirs': os.pathsep.join(default_src_dirs), 727 'search_static_first': str(self.search_static_first), 728 'extra_compile_args': '', 'extra_link_args': ''} 729 self.cp = ConfigParser(defaults) 730 self.files = [] 731 self.files.extend(get_standard_file('.numpy-site.cfg')) 732 self.files.extend(get_standard_file('site.cfg')) 733 self.parse_config_files() 734 735 if self.section is not None: 736 self.search_static_first = self.cp.getboolean( 737 self.section, 'search_static_first') 738 assert isinstance(self.search_static_first, int) 739 740 def parse_config_files(self): 741 self.cp.read(self.files) 742 if not self.cp.has_section(self.section): 743 if self.section is not None: 744 self.cp.add_section(self.section) 745 746 def calc_libraries_info(self): 747 libs = self.get_libraries() 748 dirs = self.get_lib_dirs() 749 # The extensions use runtime_library_dirs 750 r_dirs = self.get_runtime_lib_dirs() 751 # Intrinsic distutils use rpath, we simply append both entries 752 # as though they were one entry 753 r_dirs.extend(self.get_runtime_lib_dirs(key='rpath')) 754 info = {} 755 for lib in libs: 756 i = self.check_libs(dirs, [lib]) 757 if i is not None: 758 dict_append(info, **i) 759 else: 760 log.info('Library %s was not found. Ignoring' % (lib)) 761 762 if r_dirs: 763 i = self.check_libs(r_dirs, [lib]) 764 if i is not None: 765 # Swap library keywords found to runtime_library_dirs 766 # the libraries are insisting on the user having defined 767 # them using the library_dirs, and not necessarily by 768 # runtime_library_dirs 769 del i['libraries'] 770 i['runtime_library_dirs'] = i.pop('library_dirs') 771 dict_append(info, **i) 772 else: 773 log.info('Runtime library %s was not found. Ignoring' % (lib)) 774 775 return info 776 777 def set_info(self, **info): 778 if info: 779 lib_info = self.calc_libraries_info() 780 dict_append(info, **lib_info) 781 # Update extra information 782 extra_info = self.calc_extra_info() 783 dict_append(info, **extra_info) 784 self.saved_results[self.__class__.__name__] = info 785 786 def get_option_single(self, *options): 787 """ Ensure that only one of `options` are found in the section 788 789 Parameters 790 ---------- 791 *options : list of str 792 a list of options to be found in the section (``self.section``) 793 794 Returns 795 ------- 796 str : 797 the option that is uniquely found in the section 798 799 Raises 800 ------ 801 AliasedOptionError : 802 in case more than one of the options are found 803 """ 804 found = [self.cp.has_option(self.section, opt) for opt in options] 805 if sum(found) == 1: 806 return options[found.index(True)] 807 elif sum(found) == 0: 808 # nothing is found anyways 809 return options[0] 810 811 # Else we have more than 1 key found 812 if AliasedOptionError.__doc__ is None: 813 raise AliasedOptionError() 814 raise AliasedOptionError(AliasedOptionError.__doc__.format( 815 section=self.section, options='[{}]'.format(', '.join(options)))) 816 817 818 def has_info(self): 819 return self.__class__.__name__ in self.saved_results 820 821 def calc_extra_info(self): 822 """ Updates the information in the current information with 823 respect to these flags: 824 extra_compile_args 825 extra_link_args 826 """ 827 info = {} 828 for key in ['extra_compile_args', 'extra_link_args']: 829 # Get values 830 opt = self.cp.get(self.section, key) 831 opt = _shell_utils.NativeParser.split(opt) 832 if opt: 833 tmp = {key: opt} 834 dict_append(info, **tmp) 835 return info 836 837 def get_info(self, notfound_action=0): 838 """ Return a dictionary with items that are compatible 839 with numpy.distutils.setup keyword arguments. 840 """ 841 flag = 0 842 if not self.has_info(): 843 flag = 1 844 log.info(self.__class__.__name__ + ':') 845 if hasattr(self, 'calc_info'): 846 self.calc_info() 847 if notfound_action: 848 if not self.has_info(): 849 if notfound_action == 1: 850 warnings.warn(self.notfounderror.__doc__, stacklevel=2) 851 elif notfound_action == 2: 852 raise self.notfounderror(self.notfounderror.__doc__) 853 else: 854 raise ValueError(repr(notfound_action)) 855 856 if not self.has_info(): 857 log.info(' NOT AVAILABLE') 858 self.set_info() 859 else: 860 log.info(' FOUND:') 861 862 res = self.saved_results.get(self.__class__.__name__) 863 if log.get_threshold() <= log.INFO and flag: 864 for k, v in res.items(): 865 v = str(v) 866 if k in ['sources', 'libraries'] and len(v) > 270: 867 v = v[:120] + '...\n...\n...' + v[-120:] 868 log.info(' %s = %s', k, v) 869 log.info('') 870 871 return copy.deepcopy(res) 872 873 def get_paths(self, section, key): 874 dirs = self.cp.get(section, key).split(os.pathsep) 875 env_var = self.dir_env_var 876 if env_var: 877 if is_sequence(env_var): 878 e0 = env_var[-1] 879 for e in env_var: 880 if e in os.environ: 881 e0 = e 882 break 883 if not env_var[0] == e0: 884 log.info('Setting %s=%s' % (env_var[0], e0)) 885 env_var = e0 886 if env_var and env_var in os.environ: 887 d = os.environ[env_var] 888 if d == 'None': 889 log.info('Disabled %s: %s', 890 self.__class__.__name__, '(%s is None)' 891 % (env_var,)) 892 return [] 893 if os.path.isfile(d): 894 dirs = [os.path.dirname(d)] + dirs 895 l = getattr(self, '_lib_names', []) 896 if len(l) == 1: 897 b = os.path.basename(d) 898 b = os.path.splitext(b)[0] 899 if b[:3] == 'lib': 900 log.info('Replacing _lib_names[0]==%r with %r' \ 901 % (self._lib_names[0], b[3:])) 902 self._lib_names[0] = b[3:] 903 else: 904 ds = d.split(os.pathsep) 905 ds2 = [] 906 for d in ds: 907 if os.path.isdir(d): 908 ds2.append(d) 909 for dd in ['include', 'lib']: 910 d1 = os.path.join(d, dd) 911 if os.path.isdir(d1): 912 ds2.append(d1) 913 dirs = ds2 + dirs 914 default_dirs = self.cp.get(self.section, key).split(os.pathsep) 915 dirs.extend(default_dirs) 916 ret = [] 917 for d in dirs: 918 if len(d) > 0 and not os.path.isdir(d): 919 warnings.warn('Specified path %s is invalid.' % d, stacklevel=2) 920 continue 921 922 if d not in ret: 923 ret.append(d) 924 925 log.debug('( %s = %s )', key, ':'.join(ret)) 926 return ret 927 928 def get_lib_dirs(self, key='library_dirs'): 929 return self.get_paths(self.section, key) 930 931 def get_runtime_lib_dirs(self, key='runtime_library_dirs'): 932 path = self.get_paths(self.section, key) 933 if path == ['']: 934 path = [] 935 return path 936 937 def get_include_dirs(self, key='include_dirs'): 938 return self.get_paths(self.section, key) 939 940 def get_src_dirs(self, key='src_dirs'): 941 return self.get_paths(self.section, key) 942 943 def get_libs(self, key, default): 944 try: 945 libs = self.cp.get(self.section, key) 946 except NoOptionError: 947 if not default: 948 return [] 949 if is_string(default): 950 return [default] 951 return default 952 return [b for b in [a.strip() for a in libs.split(',')] if b] 953 954 def get_libraries(self, key='libraries'): 955 if hasattr(self, '_lib_names'): 956 return self.get_libs(key, default=self._lib_names) 957 else: 958 return self.get_libs(key, '') 959 960 def library_extensions(self): 961 c = customized_ccompiler() 962 static_exts = [] 963 if c.compiler_type != 'msvc': 964 # MSVC doesn't understand binutils 965 static_exts.append('.a') 966 if sys.platform == 'win32': 967 static_exts.append('.lib') # .lib is used by MSVC and others 968 if self.search_static_first: 969 exts = static_exts + [so_ext] 970 else: 971 exts = [so_ext] + static_exts 972 if sys.platform == 'cygwin': 973 exts.append('.dll.a') 974 if sys.platform == 'darwin': 975 exts.append('.dylib') 976 return exts 977 978 def check_libs(self, lib_dirs, libs, opt_libs=[]): 979 """If static or shared libraries are available then return 980 their info dictionary. 981 982 Checks for all libraries as shared libraries first, then 983 static (or vice versa if self.search_static_first is True). 984 """ 985 exts = self.library_extensions() 986 info = None 987 for ext in exts: 988 info = self._check_libs(lib_dirs, libs, opt_libs, [ext]) 989 if info is not None: 990 break 991 if not info: 992 log.info(' libraries %s not found in %s', ','.join(libs), 993 lib_dirs) 994 return info 995 996 def check_libs2(self, lib_dirs, libs, opt_libs=[]): 997 """If static or shared libraries are available then return 998 their info dictionary. 999 1000 Checks each library for shared or static. 1001 """ 1002 exts = self.library_extensions() 1003 info = self._check_libs(lib_dirs, libs, opt_libs, exts) 1004 if not info: 1005 log.info(' libraries %s not found in %s', ','.join(libs), 1006 lib_dirs) 1007 1008 return info 1009 1010 def _find_lib(self, lib_dir, lib, exts): 1011 assert is_string(lib_dir) 1012 # under windows first try without 'lib' prefix 1013 if sys.platform == 'win32': 1014 lib_prefixes = ['', 'lib'] 1015 else: 1016 lib_prefixes = ['lib'] 1017 # for each library name, see if we can find a file for it. 1018 for ext in exts: 1019 for prefix in lib_prefixes: 1020 p = self.combine_paths(lib_dir, prefix + lib + ext) 1021 if p: 1022 # p[0] is the full path to the binary library file. 1023 if is_symlink_to_accelerate(p[0]): 1024 raise RuntimeError(_accel_msg.format(filename=p[0])) 1025 break 1026 if p: 1027 assert len(p) == 1 1028 # ??? splitext on p[0] would do this for cygwin 1029 # doesn't seem correct 1030 if ext == '.dll.a': 1031 lib += '.dll' 1032 if ext == '.lib': 1033 lib = prefix + lib 1034 return lib 1035 1036 return False 1037 1038 def _find_libs(self, lib_dirs, libs, exts): 1039 # make sure we preserve the order of libs, as it can be important 1040 found_dirs, found_libs = [], [] 1041 for lib in libs: 1042 for lib_dir in lib_dirs: 1043 found_lib = self._find_lib(lib_dir, lib, exts) 1044 if found_lib: 1045 found_libs.append(found_lib) 1046 if lib_dir not in found_dirs: 1047 found_dirs.append(lib_dir) 1048 break 1049 return found_dirs, found_libs 1050 1051 def _check_libs(self, lib_dirs, libs, opt_libs, exts): 1052 """Find mandatory and optional libs in expected paths. 1053 1054 Missing optional libraries are silently forgotten. 1055 """ 1056 if not is_sequence(lib_dirs): 1057 lib_dirs = [lib_dirs] 1058 # First, try to find the mandatory libraries 1059 found_dirs, found_libs = self._find_libs(lib_dirs, libs, exts) 1060 if len(found_libs) > 0 and len(found_libs) == len(libs): 1061 # Now, check for optional libraries 1062 opt_found_dirs, opt_found_libs = self._find_libs(lib_dirs, opt_libs, exts) 1063 found_libs.extend(opt_found_libs) 1064 for lib_dir in opt_found_dirs: 1065 if lib_dir not in found_dirs: 1066 found_dirs.append(lib_dir) 1067 info = {'libraries': found_libs, 'library_dirs': found_dirs} 1068 return info 1069 else: 1070 return None 1071 1072 def combine_paths(self, *args): 1073 """Return a list of existing paths composed by all combinations 1074 of items from the arguments. 1075 """ 1076 return combine_paths(*args) 1077 1078 1079class fft_opt_info(system_info): 1080 1081 def calc_info(self): 1082 info = {} 1083 fftw_info = get_info('fftw3') or get_info('fftw2') or get_info('dfftw') 1084 djbfft_info = get_info('djbfft') 1085 if fftw_info: 1086 dict_append(info, **fftw_info) 1087 if djbfft_info: 1088 dict_append(info, **djbfft_info) 1089 self.set_info(**info) 1090 return 1091 1092 1093class fftw_info(system_info): 1094 #variables to override 1095 section = 'fftw' 1096 dir_env_var = 'FFTW' 1097 notfounderror = FFTWNotFoundError 1098 ver_info = [{'name':'fftw3', 1099 'libs':['fftw3'], 1100 'includes':['fftw3.h'], 1101 'macros':[('SCIPY_FFTW3_H', None)]}, 1102 {'name':'fftw2', 1103 'libs':['rfftw', 'fftw'], 1104 'includes':['fftw.h', 'rfftw.h'], 1105 'macros':[('SCIPY_FFTW_H', None)]}] 1106 1107 def calc_ver_info(self, ver_param): 1108 """Returns True on successful version detection, else False""" 1109 lib_dirs = self.get_lib_dirs() 1110 incl_dirs = self.get_include_dirs() 1111 1112 opt = self.get_option_single(self.section + '_libs', 'libraries') 1113 libs = self.get_libs(opt, ver_param['libs']) 1114 info = self.check_libs(lib_dirs, libs) 1115 if info is not None: 1116 flag = 0 1117 for d in incl_dirs: 1118 if len(self.combine_paths(d, ver_param['includes'])) \ 1119 == len(ver_param['includes']): 1120 dict_append(info, include_dirs=[d]) 1121 flag = 1 1122 break 1123 if flag: 1124 dict_append(info, define_macros=ver_param['macros']) 1125 else: 1126 info = None 1127 if info is not None: 1128 self.set_info(**info) 1129 return True 1130 else: 1131 log.info(' %s not found' % (ver_param['name'])) 1132 return False 1133 1134 def calc_info(self): 1135 for i in self.ver_info: 1136 if self.calc_ver_info(i): 1137 break 1138 1139 1140class fftw2_info(fftw_info): 1141 #variables to override 1142 section = 'fftw' 1143 dir_env_var = 'FFTW' 1144 notfounderror = FFTWNotFoundError 1145 ver_info = [{'name':'fftw2', 1146 'libs':['rfftw', 'fftw'], 1147 'includes':['fftw.h', 'rfftw.h'], 1148 'macros':[('SCIPY_FFTW_H', None)]} 1149 ] 1150 1151 1152class fftw3_info(fftw_info): 1153 #variables to override 1154 section = 'fftw3' 1155 dir_env_var = 'FFTW3' 1156 notfounderror = FFTWNotFoundError 1157 ver_info = [{'name':'fftw3', 1158 'libs':['fftw3'], 1159 'includes':['fftw3.h'], 1160 'macros':[('SCIPY_FFTW3_H', None)]}, 1161 ] 1162 1163 1164class dfftw_info(fftw_info): 1165 section = 'fftw' 1166 dir_env_var = 'FFTW' 1167 ver_info = [{'name':'dfftw', 1168 'libs':['drfftw', 'dfftw'], 1169 'includes':['dfftw.h', 'drfftw.h'], 1170 'macros':[('SCIPY_DFFTW_H', None)]}] 1171 1172 1173class sfftw_info(fftw_info): 1174 section = 'fftw' 1175 dir_env_var = 'FFTW' 1176 ver_info = [{'name':'sfftw', 1177 'libs':['srfftw', 'sfftw'], 1178 'includes':['sfftw.h', 'srfftw.h'], 1179 'macros':[('SCIPY_SFFTW_H', None)]}] 1180 1181 1182class fftw_threads_info(fftw_info): 1183 section = 'fftw' 1184 dir_env_var = 'FFTW' 1185 ver_info = [{'name':'fftw threads', 1186 'libs':['rfftw_threads', 'fftw_threads'], 1187 'includes':['fftw_threads.h', 'rfftw_threads.h'], 1188 'macros':[('SCIPY_FFTW_THREADS_H', None)]}] 1189 1190 1191class dfftw_threads_info(fftw_info): 1192 section = 'fftw' 1193 dir_env_var = 'FFTW' 1194 ver_info = [{'name':'dfftw threads', 1195 'libs':['drfftw_threads', 'dfftw_threads'], 1196 'includes':['dfftw_threads.h', 'drfftw_threads.h'], 1197 'macros':[('SCIPY_DFFTW_THREADS_H', None)]}] 1198 1199 1200class sfftw_threads_info(fftw_info): 1201 section = 'fftw' 1202 dir_env_var = 'FFTW' 1203 ver_info = [{'name':'sfftw threads', 1204 'libs':['srfftw_threads', 'sfftw_threads'], 1205 'includes':['sfftw_threads.h', 'srfftw_threads.h'], 1206 'macros':[('SCIPY_SFFTW_THREADS_H', None)]}] 1207 1208 1209class djbfft_info(system_info): 1210 section = 'djbfft' 1211 dir_env_var = 'DJBFFT' 1212 notfounderror = DJBFFTNotFoundError 1213 1214 def get_paths(self, section, key): 1215 pre_dirs = system_info.get_paths(self, section, key) 1216 dirs = [] 1217 for d in pre_dirs: 1218 dirs.extend(self.combine_paths(d, ['djbfft']) + [d]) 1219 return [d for d in dirs if os.path.isdir(d)] 1220 1221 def calc_info(self): 1222 lib_dirs = self.get_lib_dirs() 1223 incl_dirs = self.get_include_dirs() 1224 info = None 1225 for d in lib_dirs: 1226 p = self.combine_paths(d, ['djbfft.a']) 1227 if p: 1228 info = {'extra_objects': p} 1229 break 1230 p = self.combine_paths(d, ['libdjbfft.a', 'libdjbfft' + so_ext]) 1231 if p: 1232 info = {'libraries': ['djbfft'], 'library_dirs': [d]} 1233 break 1234 if info is None: 1235 return 1236 for d in incl_dirs: 1237 if len(self.combine_paths(d, ['fftc8.h', 'fftfreq.h'])) == 2: 1238 dict_append(info, include_dirs=[d], 1239 define_macros=[('SCIPY_DJBFFT_H', None)]) 1240 self.set_info(**info) 1241 return 1242 return 1243 1244 1245class mkl_info(system_info): 1246 section = 'mkl' 1247 dir_env_var = 'MKLROOT' 1248 _lib_mkl = ['mkl_rt'] 1249 1250 def get_mkl_rootdir(self): 1251 mklroot = os.environ.get('MKLROOT', None) 1252 if mklroot is not None: 1253 return mklroot 1254 paths = os.environ.get('LD_LIBRARY_PATH', '').split(os.pathsep) 1255 ld_so_conf = '/etc/ld.so.conf' 1256 if os.path.isfile(ld_so_conf): 1257 with open(ld_so_conf, 'r') as f: 1258 for d in f: 1259 d = d.strip() 1260 if d: 1261 paths.append(d) 1262 intel_mkl_dirs = [] 1263 for path in paths: 1264 path_atoms = path.split(os.sep) 1265 for m in path_atoms: 1266 if m.startswith('mkl'): 1267 d = os.sep.join(path_atoms[:path_atoms.index(m) + 2]) 1268 intel_mkl_dirs.append(d) 1269 break 1270 for d in paths: 1271 dirs = glob(os.path.join(d, 'mkl', '*')) 1272 dirs += glob(os.path.join(d, 'mkl*')) 1273 for sub_dir in dirs: 1274 if os.path.isdir(os.path.join(sub_dir, 'lib')): 1275 return sub_dir 1276 return None 1277 1278 def __init__(self): 1279 mklroot = self.get_mkl_rootdir() 1280 if mklroot is None: 1281 system_info.__init__(self) 1282 else: 1283 from .cpuinfo import cpu 1284 if cpu.is_Itanium(): 1285 plt = '64' 1286 elif cpu.is_Intel() and cpu.is_64bit(): 1287 plt = 'intel64' 1288 else: 1289 plt = '32' 1290 system_info.__init__( 1291 self, 1292 default_lib_dirs=[os.path.join(mklroot, 'lib', plt)], 1293 default_include_dirs=[os.path.join(mklroot, 'include')]) 1294 1295 def calc_info(self): 1296 lib_dirs = self.get_lib_dirs() 1297 incl_dirs = self.get_include_dirs() 1298 opt = self.get_option_single('mkl_libs', 'libraries') 1299 mkl_libs = self.get_libs(opt, self._lib_mkl) 1300 info = self.check_libs2(lib_dirs, mkl_libs) 1301 if info is None: 1302 return 1303 dict_append(info, 1304 define_macros=[('SCIPY_MKL_H', None), 1305 ('HAVE_CBLAS', None)], 1306 include_dirs=incl_dirs) 1307 if sys.platform == 'win32': 1308 pass # win32 has no pthread library 1309 else: 1310 dict_append(info, libraries=['pthread']) 1311 self.set_info(**info) 1312 1313 1314class lapack_mkl_info(mkl_info): 1315 pass 1316 1317 1318class blas_mkl_info(mkl_info): 1319 pass 1320 1321 1322class atlas_info(system_info): 1323 section = 'atlas' 1324 dir_env_var = 'ATLAS' 1325 _lib_names = ['f77blas', 'cblas'] 1326 if sys.platform[:7] == 'freebsd': 1327 _lib_atlas = ['atlas'] 1328 _lib_lapack = ['alapack'] 1329 else: 1330 _lib_atlas = ['atlas'] 1331 _lib_lapack = ['lapack'] 1332 1333 notfounderror = AtlasNotFoundError 1334 1335 def get_paths(self, section, key): 1336 pre_dirs = system_info.get_paths(self, section, key) 1337 dirs = [] 1338 for d in pre_dirs: 1339 dirs.extend(self.combine_paths(d, ['atlas*', 'ATLAS*', 1340 'sse', '3dnow', 'sse2']) + [d]) 1341 return [d for d in dirs if os.path.isdir(d)] 1342 1343 def calc_info(self): 1344 lib_dirs = self.get_lib_dirs() 1345 info = {} 1346 opt = self.get_option_single('atlas_libs', 'libraries') 1347 atlas_libs = self.get_libs(opt, self._lib_names + self._lib_atlas) 1348 lapack_libs = self.get_libs('lapack_libs', self._lib_lapack) 1349 atlas = None 1350 lapack = None 1351 atlas_1 = None 1352 for d in lib_dirs: 1353 # FIXME: lapack_atlas is unused 1354 lapack_atlas = self.check_libs2(d, ['lapack_atlas'], []) 1355 atlas = self.check_libs2(d, atlas_libs, []) 1356 if atlas is not None: 1357 lib_dirs2 = [d] + self.combine_paths(d, ['atlas*', 'ATLAS*']) 1358 lapack = self.check_libs2(lib_dirs2, lapack_libs, []) 1359 if lapack is not None: 1360 break 1361 if atlas: 1362 atlas_1 = atlas 1363 log.info(self.__class__) 1364 if atlas is None: 1365 atlas = atlas_1 1366 if atlas is None: 1367 return 1368 include_dirs = self.get_include_dirs() 1369 h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None]) 1370 h = h[0] 1371 if h: 1372 h = os.path.dirname(h) 1373 dict_append(info, include_dirs=[h]) 1374 info['language'] = 'c' 1375 if lapack is not None: 1376 dict_append(info, **lapack) 1377 dict_append(info, **atlas) 1378 elif 'lapack_atlas' in atlas['libraries']: 1379 dict_append(info, **atlas) 1380 dict_append(info, 1381 define_macros=[('ATLAS_WITH_LAPACK_ATLAS', None)]) 1382 self.set_info(**info) 1383 return 1384 else: 1385 dict_append(info, **atlas) 1386 dict_append(info, define_macros=[('ATLAS_WITHOUT_LAPACK', None)]) 1387 message = textwrap.dedent(""" 1388 ********************************************************************* 1389 Could not find lapack library within the ATLAS installation. 1390 ********************************************************************* 1391 """) 1392 warnings.warn(message, stacklevel=2) 1393 self.set_info(**info) 1394 return 1395 1396 # Check if lapack library is complete, only warn if it is not. 1397 lapack_dir = lapack['library_dirs'][0] 1398 lapack_name = lapack['libraries'][0] 1399 lapack_lib = None 1400 lib_prefixes = ['lib'] 1401 if sys.platform == 'win32': 1402 lib_prefixes.append('') 1403 for e in self.library_extensions(): 1404 for prefix in lib_prefixes: 1405 fn = os.path.join(lapack_dir, prefix + lapack_name + e) 1406 if os.path.exists(fn): 1407 lapack_lib = fn 1408 break 1409 if lapack_lib: 1410 break 1411 if lapack_lib is not None: 1412 sz = os.stat(lapack_lib)[6] 1413 if sz <= 4000 * 1024: 1414 message = textwrap.dedent(""" 1415 ********************************************************************* 1416 Lapack library (from ATLAS) is probably incomplete: 1417 size of %s is %sk (expected >4000k) 1418 1419 Follow the instructions in the KNOWN PROBLEMS section of the file 1420 numpy/INSTALL.txt. 1421 ********************************************************************* 1422 """) % (lapack_lib, sz / 1024) 1423 warnings.warn(message, stacklevel=2) 1424 else: 1425 info['language'] = 'f77' 1426 1427 atlas_version, atlas_extra_info = get_atlas_version(**atlas) 1428 dict_append(info, **atlas_extra_info) 1429 1430 self.set_info(**info) 1431 1432 1433class atlas_blas_info(atlas_info): 1434 _lib_names = ['f77blas', 'cblas'] 1435 1436 def calc_info(self): 1437 lib_dirs = self.get_lib_dirs() 1438 info = {} 1439 opt = self.get_option_single('atlas_libs', 'libraries') 1440 atlas_libs = self.get_libs(opt, self._lib_names + self._lib_atlas) 1441 atlas = self.check_libs2(lib_dirs, atlas_libs, []) 1442 if atlas is None: 1443 return 1444 include_dirs = self.get_include_dirs() 1445 h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None]) 1446 h = h[0] 1447 if h: 1448 h = os.path.dirname(h) 1449 dict_append(info, include_dirs=[h]) 1450 info['language'] = 'c' 1451 info['define_macros'] = [('HAVE_CBLAS', None)] 1452 1453 atlas_version, atlas_extra_info = get_atlas_version(**atlas) 1454 dict_append(atlas, **atlas_extra_info) 1455 1456 dict_append(info, **atlas) 1457 1458 self.set_info(**info) 1459 return 1460 1461 1462class atlas_threads_info(atlas_info): 1463 dir_env_var = ['PTATLAS', 'ATLAS'] 1464 _lib_names = ['ptf77blas', 'ptcblas'] 1465 1466 1467class atlas_blas_threads_info(atlas_blas_info): 1468 dir_env_var = ['PTATLAS', 'ATLAS'] 1469 _lib_names = ['ptf77blas', 'ptcblas'] 1470 1471 1472class lapack_atlas_info(atlas_info): 1473 _lib_names = ['lapack_atlas'] + atlas_info._lib_names 1474 1475 1476class lapack_atlas_threads_info(atlas_threads_info): 1477 _lib_names = ['lapack_atlas'] + atlas_threads_info._lib_names 1478 1479 1480class atlas_3_10_info(atlas_info): 1481 _lib_names = ['satlas'] 1482 _lib_atlas = _lib_names 1483 _lib_lapack = _lib_names 1484 1485 1486class atlas_3_10_blas_info(atlas_3_10_info): 1487 _lib_names = ['satlas'] 1488 1489 def calc_info(self): 1490 lib_dirs = self.get_lib_dirs() 1491 info = {} 1492 opt = self.get_option_single('atlas_lib', 'libraries') 1493 atlas_libs = self.get_libs(opt, self._lib_names) 1494 atlas = self.check_libs2(lib_dirs, atlas_libs, []) 1495 if atlas is None: 1496 return 1497 include_dirs = self.get_include_dirs() 1498 h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None]) 1499 h = h[0] 1500 if h: 1501 h = os.path.dirname(h) 1502 dict_append(info, include_dirs=[h]) 1503 info['language'] = 'c' 1504 info['define_macros'] = [('HAVE_CBLAS', None)] 1505 1506 atlas_version, atlas_extra_info = get_atlas_version(**atlas) 1507 dict_append(atlas, **atlas_extra_info) 1508 1509 dict_append(info, **atlas) 1510 1511 self.set_info(**info) 1512 return 1513 1514 1515class atlas_3_10_threads_info(atlas_3_10_info): 1516 dir_env_var = ['PTATLAS', 'ATLAS'] 1517 _lib_names = ['tatlas'] 1518 _lib_atlas = _lib_names 1519 _lib_lapack = _lib_names 1520 1521 1522class atlas_3_10_blas_threads_info(atlas_3_10_blas_info): 1523 dir_env_var = ['PTATLAS', 'ATLAS'] 1524 _lib_names = ['tatlas'] 1525 1526 1527class lapack_atlas_3_10_info(atlas_3_10_info): 1528 pass 1529 1530 1531class lapack_atlas_3_10_threads_info(atlas_3_10_threads_info): 1532 pass 1533 1534 1535class lapack_info(system_info): 1536 section = 'lapack' 1537 dir_env_var = 'LAPACK' 1538 _lib_names = ['lapack'] 1539 notfounderror = LapackNotFoundError 1540 1541 def calc_info(self): 1542 lib_dirs = self.get_lib_dirs() 1543 1544 opt = self.get_option_single('lapack_libs', 'libraries') 1545 lapack_libs = self.get_libs(opt, self._lib_names) 1546 info = self.check_libs(lib_dirs, lapack_libs, []) 1547 if info is None: 1548 return 1549 info['language'] = 'f77' 1550 self.set_info(**info) 1551 1552 1553class lapack_src_info(system_info): 1554 section = 'lapack_src' 1555 dir_env_var = 'LAPACK_SRC' 1556 notfounderror = LapackSrcNotFoundError 1557 1558 def get_paths(self, section, key): 1559 pre_dirs = system_info.get_paths(self, section, key) 1560 dirs = [] 1561 for d in pre_dirs: 1562 dirs.extend([d] + self.combine_paths(d, ['LAPACK*/SRC', 'SRC'])) 1563 return [d for d in dirs if os.path.isdir(d)] 1564 1565 def calc_info(self): 1566 src_dirs = self.get_src_dirs() 1567 src_dir = '' 1568 for d in src_dirs: 1569 if os.path.isfile(os.path.join(d, 'dgesv.f')): 1570 src_dir = d 1571 break 1572 if not src_dir: 1573 #XXX: Get sources from netlib. May be ask first. 1574 return 1575 # The following is extracted from LAPACK-3.0/SRC/Makefile. 1576 # Added missing names from lapack-lite-3.1.1/SRC/Makefile 1577 # while keeping removed names for Lapack-3.0 compatibility. 1578 allaux = ''' 1579 ilaenv ieeeck lsame lsamen xerbla 1580 iparmq 1581 ''' # *.f 1582 laux = ''' 1583 bdsdc bdsqr disna labad lacpy ladiv lae2 laebz laed0 laed1 1584 laed2 laed3 laed4 laed5 laed6 laed7 laed8 laed9 laeda laev2 1585 lagtf lagts lamch lamrg lanst lapy2 lapy3 larnv larrb larre 1586 larrf lartg laruv las2 lascl lasd0 lasd1 lasd2 lasd3 lasd4 1587 lasd5 lasd6 lasd7 lasd8 lasd9 lasda lasdq lasdt laset lasq1 1588 lasq2 lasq3 lasq4 lasq5 lasq6 lasr lasrt lassq lasv2 pttrf 1589 stebz stedc steqr sterf 1590 1591 larra larrc larrd larr larrk larrj larrr laneg laisnan isnan 1592 lazq3 lazq4 1593 ''' # [s|d]*.f 1594 lasrc = ''' 1595 gbbrd gbcon gbequ gbrfs gbsv gbsvx gbtf2 gbtrf gbtrs gebak 1596 gebal gebd2 gebrd gecon geequ gees geesx geev geevx gegs gegv 1597 gehd2 gehrd gelq2 gelqf gels gelsd gelss gelsx gelsy geql2 1598 geqlf geqp3 geqpf geqr2 geqrf gerfs gerq2 gerqf gesc2 gesdd 1599 gesv gesvd gesvx getc2 getf2 getrf getri getrs ggbak ggbal 1600 gges ggesx ggev ggevx ggglm gghrd gglse ggqrf ggrqf ggsvd 1601 ggsvp gtcon gtrfs gtsv gtsvx gttrf gttrs gtts2 hgeqz hsein 1602 hseqr labrd lacon laein lags2 lagtm lahqr lahrd laic1 lals0 1603 lalsa lalsd langb lange langt lanhs lansb lansp lansy lantb 1604 lantp lantr lapll lapmt laqgb laqge laqp2 laqps laqsb laqsp 1605 laqsy lar1v lar2v larf larfb larfg larft larfx largv larrv 1606 lartv larz larzb larzt laswp lasyf latbs latdf latps latrd 1607 latrs latrz latzm lauu2 lauum pbcon pbequ pbrfs pbstf pbsv 1608 pbsvx pbtf2 pbtrf pbtrs pocon poequ porfs posv posvx potf2 1609 potrf potri potrs ppcon ppequ pprfs ppsv ppsvx pptrf pptri 1610 pptrs ptcon pteqr ptrfs ptsv ptsvx pttrs ptts2 spcon sprfs 1611 spsv spsvx sptrf sptri sptrs stegr stein sycon syrfs sysv 1612 sysvx sytf2 sytrf sytri sytrs tbcon tbrfs tbtrs tgevc tgex2 1613 tgexc tgsen tgsja tgsna tgsy2 tgsyl tpcon tprfs tptri tptrs 1614 trcon trevc trexc trrfs trsen trsna trsyl trti2 trtri trtrs 1615 tzrqf tzrzf 1616 1617 lacn2 lahr2 stemr laqr0 laqr1 laqr2 laqr3 laqr4 laqr5 1618 ''' # [s|c|d|z]*.f 1619 sd_lasrc = ''' 1620 laexc lag2 lagv2 laln2 lanv2 laqtr lasy2 opgtr opmtr org2l 1621 org2r orgbr orghr orgl2 orglq orgql orgqr orgr2 orgrq orgtr 1622 orm2l orm2r ormbr ormhr orml2 ormlq ormql ormqr ormr2 ormr3 1623 ormrq ormrz ormtr rscl sbev sbevd sbevx sbgst sbgv sbgvd sbgvx 1624 sbtrd spev spevd spevx spgst spgv spgvd spgvx sptrd stev stevd 1625 stevr stevx syev syevd syevr syevx sygs2 sygst sygv sygvd 1626 sygvx sytd2 sytrd 1627 ''' # [s|d]*.f 1628 cz_lasrc = ''' 1629 bdsqr hbev hbevd hbevx hbgst hbgv hbgvd hbgvx hbtrd hecon heev 1630 heevd heevr heevx hegs2 hegst hegv hegvd hegvx herfs hesv 1631 hesvx hetd2 hetf2 hetrd hetrf hetri hetrs hpcon hpev hpevd 1632 hpevx hpgst hpgv hpgvd hpgvx hprfs hpsv hpsvx hptrd hptrf 1633 hptri hptrs lacgv lacp2 lacpy lacrm lacrt ladiv laed0 laed7 1634 laed8 laesy laev2 lahef lanhb lanhe lanhp lanht laqhb laqhe 1635 laqhp larcm larnv lartg lascl laset lasr lassq pttrf rot spmv 1636 spr stedc steqr symv syr ung2l ung2r ungbr unghr ungl2 unglq 1637 ungql ungqr ungr2 ungrq ungtr unm2l unm2r unmbr unmhr unml2 1638 unmlq unmql unmqr unmr2 unmr3 unmrq unmrz unmtr upgtr upmtr 1639 ''' # [c|z]*.f 1640 ####### 1641 sclaux = laux + ' econd ' # s*.f 1642 dzlaux = laux + ' secnd ' # d*.f 1643 slasrc = lasrc + sd_lasrc # s*.f 1644 dlasrc = lasrc + sd_lasrc # d*.f 1645 clasrc = lasrc + cz_lasrc + ' srot srscl ' # c*.f 1646 zlasrc = lasrc + cz_lasrc + ' drot drscl ' # z*.f 1647 oclasrc = ' icmax1 scsum1 ' # *.f 1648 ozlasrc = ' izmax1 dzsum1 ' # *.f 1649 sources = ['s%s.f' % f for f in (sclaux + slasrc).split()] \ 1650 + ['d%s.f' % f for f in (dzlaux + dlasrc).split()] \ 1651 + ['c%s.f' % f for f in (clasrc).split()] \ 1652 + ['z%s.f' % f for f in (zlasrc).split()] \ 1653 + ['%s.f' % f for f in (allaux + oclasrc + ozlasrc).split()] 1654 sources = [os.path.join(src_dir, f) for f in sources] 1655 # Lapack 3.1: 1656 src_dir2 = os.path.join(src_dir, '..', 'INSTALL') 1657 sources += [os.path.join(src_dir2, p + 'lamch.f') for p in 'sdcz'] 1658 # Lapack 3.2.1: 1659 sources += [os.path.join(src_dir, p + 'larfp.f') for p in 'sdcz'] 1660 sources += [os.path.join(src_dir, 'ila' + p + 'lr.f') for p in 'sdcz'] 1661 sources += [os.path.join(src_dir, 'ila' + p + 'lc.f') for p in 'sdcz'] 1662 # Should we check here actual existence of source files? 1663 # Yes, the file listing is different between 3.0 and 3.1 1664 # versions. 1665 sources = [f for f in sources if os.path.isfile(f)] 1666 info = {'sources': sources, 'language': 'f77'} 1667 self.set_info(**info) 1668 1669atlas_version_c_text = r''' 1670/* This file is generated from numpy/distutils/system_info.py */ 1671void ATL_buildinfo(void); 1672int main(void) { 1673 ATL_buildinfo(); 1674 return 0; 1675} 1676''' 1677 1678_cached_atlas_version = {} 1679 1680 1681def get_atlas_version(**config): 1682 libraries = config.get('libraries', []) 1683 library_dirs = config.get('library_dirs', []) 1684 key = (tuple(libraries), tuple(library_dirs)) 1685 if key in _cached_atlas_version: 1686 return _cached_atlas_version[key] 1687 c = cmd_config(Distribution()) 1688 atlas_version = None 1689 info = {} 1690 try: 1691 s, o = c.get_output(atlas_version_c_text, 1692 libraries=libraries, library_dirs=library_dirs, 1693 ) 1694 if s and re.search(r'undefined reference to `_gfortran', o, re.M): 1695 s, o = c.get_output(atlas_version_c_text, 1696 libraries=libraries + ['gfortran'], 1697 library_dirs=library_dirs, 1698 ) 1699 if not s: 1700 warnings.warn(textwrap.dedent(""" 1701 ***************************************************** 1702 Linkage with ATLAS requires gfortran. Use 1703 1704 python setup.py config_fc --fcompiler=gnu95 ... 1705 1706 when building extension libraries that use ATLAS. 1707 Make sure that -lgfortran is used for C++ extensions. 1708 ***************************************************** 1709 """), stacklevel=2) 1710 dict_append(info, language='f90', 1711 define_macros=[('ATLAS_REQUIRES_GFORTRAN', None)]) 1712 except Exception: # failed to get version from file -- maybe on Windows 1713 # look at directory name 1714 for o in library_dirs: 1715 m = re.search(r'ATLAS_(?P<version>\d+[.]\d+[.]\d+)_', o) 1716 if m: 1717 atlas_version = m.group('version') 1718 if atlas_version is not None: 1719 break 1720 1721 # final choice --- look at ATLAS_VERSION environment 1722 # variable 1723 if atlas_version is None: 1724 atlas_version = os.environ.get('ATLAS_VERSION', None) 1725 if atlas_version: 1726 dict_append(info, define_macros=[( 1727 'ATLAS_INFO', _c_string_literal(atlas_version)) 1728 ]) 1729 else: 1730 dict_append(info, define_macros=[('NO_ATLAS_INFO', -1)]) 1731 return atlas_version or '?.?.?', info 1732 1733 if not s: 1734 m = re.search(r'ATLAS version (?P<version>\d+[.]\d+[.]\d+)', o) 1735 if m: 1736 atlas_version = m.group('version') 1737 if atlas_version is None: 1738 if re.search(r'undefined symbol: ATL_buildinfo', o, re.M): 1739 atlas_version = '3.2.1_pre3.3.6' 1740 else: 1741 log.info('Status: %d', s) 1742 log.info('Output: %s', o) 1743 1744 elif atlas_version == '3.2.1_pre3.3.6': 1745 dict_append(info, define_macros=[('NO_ATLAS_INFO', -2)]) 1746 else: 1747 dict_append(info, define_macros=[( 1748 'ATLAS_INFO', _c_string_literal(atlas_version)) 1749 ]) 1750 result = _cached_atlas_version[key] = atlas_version, info 1751 return result 1752 1753 1754class lapack_opt_info(system_info): 1755 notfounderror = LapackNotFoundError 1756 # List of all known LAPACK libraries, in the default order 1757 lapack_order = ['mkl', 'openblas', 'flame', 'atlas', 'lapack'] 1758 order_env_var_name = 'NPY_LAPACK_ORDER' 1759 1760 def _calc_info_mkl(self): 1761 info = get_info('lapack_mkl') 1762 if info: 1763 self.set_info(**info) 1764 return True 1765 return False 1766 1767 def _calc_info_openblas(self): 1768 info = get_info('openblas_lapack') 1769 if info: 1770 self.set_info(**info) 1771 return True 1772 info = get_info('openblas_clapack') 1773 if info: 1774 self.set_info(**info) 1775 return True 1776 return False 1777 1778 def _calc_info_flame(self): 1779 info = get_info('flame') 1780 if info: 1781 self.set_info(**info) 1782 return True 1783 return False 1784 1785 def _calc_info_atlas(self): 1786 info = get_info('atlas_3_10_threads') 1787 if not info: 1788 info = get_info('atlas_3_10') 1789 if not info: 1790 info = get_info('atlas_threads') 1791 if not info: 1792 info = get_info('atlas') 1793 if info: 1794 # Figure out if ATLAS has lapack... 1795 # If not we need the lapack library, but not BLAS! 1796 l = info.get('define_macros', []) 1797 if ('ATLAS_WITH_LAPACK_ATLAS', None) in l \ 1798 or ('ATLAS_WITHOUT_LAPACK', None) in l: 1799 # Get LAPACK (with possible warnings) 1800 # If not found we don't accept anything 1801 # since we can't use ATLAS with LAPACK! 1802 lapack_info = self._get_info_lapack() 1803 if not lapack_info: 1804 return False 1805 dict_append(info, **lapack_info) 1806 self.set_info(**info) 1807 return True 1808 return False 1809 1810 def _calc_info_accelerate(self): 1811 info = get_info('accelerate') 1812 if info: 1813 self.set_info(**info) 1814 return True 1815 return False 1816 1817 def _get_info_blas(self): 1818 # Default to get the optimized BLAS implementation 1819 info = get_info('blas_opt') 1820 if not info: 1821 warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=3) 1822 info_src = get_info('blas_src') 1823 if not info_src: 1824 warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=3) 1825 return {} 1826 dict_append(info, libraries=[('fblas_src', info_src)]) 1827 return info 1828 1829 def _get_info_lapack(self): 1830 info = get_info('lapack') 1831 if not info: 1832 warnings.warn(LapackNotFoundError.__doc__ or '', stacklevel=3) 1833 info_src = get_info('lapack_src') 1834 if not info_src: 1835 warnings.warn(LapackSrcNotFoundError.__doc__ or '', stacklevel=3) 1836 return {} 1837 dict_append(info, libraries=[('flapack_src', info_src)]) 1838 return info 1839 1840 def _calc_info_lapack(self): 1841 info = self._get_info_lapack() 1842 if info: 1843 info_blas = self._get_info_blas() 1844 dict_append(info, **info_blas) 1845 dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) 1846 self.set_info(**info) 1847 return True 1848 return False 1849 1850 def _calc_info(self, name): 1851 return getattr(self, '_calc_info_{}'.format(name))() 1852 1853 def calc_info(self): 1854 lapack_order, unknown_order = _parse_env_order(self.lapack_order, self.order_env_var_name) 1855 if len(unknown_order) > 0: 1856 raise ValueError("lapack_opt_info user defined " 1857 "LAPACK order has unacceptable " 1858 "values: {}".format(unknown_order)) 1859 1860 for lapack in lapack_order: 1861 if self._calc_info(lapack): 1862 return 1863 1864 if 'lapack' not in lapack_order: 1865 # Since the user may request *not* to use any library, we still need 1866 # to raise warnings to signal missing packages! 1867 warnings.warn(LapackNotFoundError.__doc__ or '', stacklevel=2) 1868 warnings.warn(LapackSrcNotFoundError.__doc__ or '', stacklevel=2) 1869 1870 1871class _ilp64_opt_info_mixin: 1872 symbol_suffix = None 1873 symbol_prefix = None 1874 1875 def _check_info(self, info): 1876 macros = dict(info.get('define_macros', [])) 1877 prefix = macros.get('BLAS_SYMBOL_PREFIX', '') 1878 suffix = macros.get('BLAS_SYMBOL_SUFFIX', '') 1879 1880 if self.symbol_prefix not in (None, prefix): 1881 return False 1882 1883 if self.symbol_suffix not in (None, suffix): 1884 return False 1885 1886 return bool(info) 1887 1888 1889class lapack_ilp64_opt_info(lapack_opt_info, _ilp64_opt_info_mixin): 1890 notfounderror = LapackILP64NotFoundError 1891 lapack_order = ['openblas64_', 'openblas_ilp64'] 1892 order_env_var_name = 'NPY_LAPACK_ILP64_ORDER' 1893 1894 def _calc_info(self, name): 1895 info = get_info(name + '_lapack') 1896 if self._check_info(info): 1897 self.set_info(**info) 1898 return True 1899 return False 1900 1901 1902class lapack_ilp64_plain_opt_info(lapack_ilp64_opt_info): 1903 # Same as lapack_ilp64_opt_info, but fix symbol names 1904 symbol_prefix = '' 1905 symbol_suffix = '' 1906 1907 1908class lapack64__opt_info(lapack_ilp64_opt_info): 1909 symbol_prefix = '' 1910 symbol_suffix = '64_' 1911 1912 1913class blas_opt_info(system_info): 1914 notfounderror = BlasNotFoundError 1915 # List of all known BLAS libraries, in the default order 1916 blas_order = ['mkl', 'blis', 'openblas', 'atlas', 'blas'] 1917 order_env_var_name = 'NPY_BLAS_ORDER' 1918 1919 def _calc_info_mkl(self): 1920 info = get_info('blas_mkl') 1921 if info: 1922 self.set_info(**info) 1923 return True 1924 return False 1925 1926 def _calc_info_blis(self): 1927 info = get_info('blis') 1928 if info: 1929 self.set_info(**info) 1930 return True 1931 return False 1932 1933 def _calc_info_openblas(self): 1934 info = get_info('openblas') 1935 if info: 1936 self.set_info(**info) 1937 return True 1938 return False 1939 1940 def _calc_info_atlas(self): 1941 info = get_info('atlas_3_10_blas_threads') 1942 if not info: 1943 info = get_info('atlas_3_10_blas') 1944 if not info: 1945 info = get_info('atlas_blas_threads') 1946 if not info: 1947 info = get_info('atlas_blas') 1948 if info: 1949 self.set_info(**info) 1950 return True 1951 return False 1952 1953 def _calc_info_accelerate(self): 1954 info = get_info('accelerate') 1955 if info: 1956 self.set_info(**info) 1957 return True 1958 return False 1959 1960 def _calc_info_blas(self): 1961 # Warn about a non-optimized BLAS library 1962 warnings.warn(BlasOptNotFoundError.__doc__ or '', stacklevel=3) 1963 info = {} 1964 dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) 1965 1966 blas = get_info('blas') 1967 if blas: 1968 dict_append(info, **blas) 1969 else: 1970 # Not even BLAS was found! 1971 warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=3) 1972 1973 blas_src = get_info('blas_src') 1974 if not blas_src: 1975 warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=3) 1976 return False 1977 dict_append(info, libraries=[('fblas_src', blas_src)]) 1978 1979 self.set_info(**info) 1980 return True 1981 1982 def _calc_info(self, name): 1983 return getattr(self, '_calc_info_{}'.format(name))() 1984 1985 def calc_info(self): 1986 blas_order, unknown_order = _parse_env_order(self.blas_order, self.order_env_var_name) 1987 if len(unknown_order) > 0: 1988 raise ValueError("blas_opt_info user defined BLAS order has unacceptable values: {}".format(unknown_order)) 1989 1990 for blas in blas_order: 1991 if self._calc_info(blas): 1992 return 1993 1994 if 'blas' not in blas_order: 1995 # Since the user may request *not* to use any library, we still need 1996 # to raise warnings to signal missing packages! 1997 warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=2) 1998 warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=2) 1999 2000 2001class blas_ilp64_opt_info(blas_opt_info, _ilp64_opt_info_mixin): 2002 notfounderror = BlasILP64NotFoundError 2003 blas_order = ['openblas64_', 'openblas_ilp64'] 2004 order_env_var_name = 'NPY_BLAS_ILP64_ORDER' 2005 2006 def _calc_info(self, name): 2007 info = get_info(name) 2008 if self._check_info(info): 2009 self.set_info(**info) 2010 return True 2011 return False 2012 2013 2014class blas_ilp64_plain_opt_info(blas_ilp64_opt_info): 2015 symbol_prefix = '' 2016 symbol_suffix = '' 2017 2018 2019class blas64__opt_info(blas_ilp64_opt_info): 2020 symbol_prefix = '' 2021 symbol_suffix = '64_' 2022 2023 2024class cblas_info(system_info): 2025 section = 'cblas' 2026 dir_env_var = 'CBLAS' 2027 # No default as it's used only in blas_info 2028 _lib_names = [] 2029 notfounderror = BlasNotFoundError 2030 2031 2032class blas_info(system_info): 2033 section = 'blas' 2034 dir_env_var = 'BLAS' 2035 _lib_names = ['blas'] 2036 notfounderror = BlasNotFoundError 2037 2038 def calc_info(self): 2039 lib_dirs = self.get_lib_dirs() 2040 opt = self.get_option_single('blas_libs', 'libraries') 2041 blas_libs = self.get_libs(opt, self._lib_names) 2042 info = self.check_libs(lib_dirs, blas_libs, []) 2043 if info is None: 2044 return 2045 else: 2046 info['include_dirs'] = self.get_include_dirs() 2047 if platform.system() == 'Windows': 2048 # The check for windows is needed because get_cblas_libs uses the 2049 # same compiler that was used to compile Python and msvc is 2050 # often not installed when mingw is being used. This rough 2051 # treatment is not desirable, but windows is tricky. 2052 info['language'] = 'f77' # XXX: is it generally true? 2053 # If cblas is given as an option, use those 2054 cblas_info_obj = cblas_info() 2055 cblas_opt = cblas_info_obj.get_option_single('cblas_libs', 'libraries') 2056 cblas_libs = cblas_info_obj.get_libs(cblas_opt, None) 2057 if cblas_libs: 2058 info['libraries'] = cblas_libs + blas_libs 2059 info['define_macros'] = [('HAVE_CBLAS', None)] 2060 else: 2061 lib = self.get_cblas_libs(info) 2062 if lib is not None: 2063 info['language'] = 'c' 2064 info['libraries'] = lib 2065 info['define_macros'] = [('HAVE_CBLAS', None)] 2066 self.set_info(**info) 2067 2068 def get_cblas_libs(self, info): 2069 """ Check whether we can link with CBLAS interface 2070 2071 This method will search through several combinations of libraries 2072 to check whether CBLAS is present: 2073 2074 1. Libraries in ``info['libraries']``, as is 2075 2. As 1. but also explicitly adding ``'cblas'`` as a library 2076 3. As 1. but also explicitly adding ``'blas'`` as a library 2077 4. Check only library ``'cblas'`` 2078 5. Check only library ``'blas'`` 2079 2080 Parameters 2081 ---------- 2082 info : dict 2083 system information dictionary for compilation and linking 2084 2085 Returns 2086 ------- 2087 libraries : list of str or None 2088 a list of libraries that enables the use of CBLAS interface. 2089 Returns None if not found or a compilation error occurs. 2090 2091 Since 1.17 returns a list. 2092 """ 2093 # primitive cblas check by looking for the header and trying to link 2094 # cblas or blas 2095 c = customized_ccompiler() 2096 tmpdir = tempfile.mkdtemp() 2097 s = textwrap.dedent("""\ 2098 #include <cblas.h> 2099 int main(int argc, const char *argv[]) 2100 { 2101 double a[4] = {1,2,3,4}; 2102 double b[4] = {5,6,7,8}; 2103 return cblas_ddot(4, a, 1, b, 1) > 10; 2104 }""") 2105 src = os.path.join(tmpdir, 'source.c') 2106 try: 2107 with open(src, 'wt') as f: 2108 f.write(s) 2109 2110 try: 2111 # check we can compile (find headers) 2112 obj = c.compile([src], output_dir=tmpdir, 2113 include_dirs=self.get_include_dirs()) 2114 except (distutils.ccompiler.CompileError, distutils.ccompiler.LinkError): 2115 return None 2116 2117 # check we can link (find library) 2118 # some systems have separate cblas and blas libs. 2119 for libs in [info['libraries'], ['cblas'] + info['libraries'], 2120 ['blas'] + info['libraries'], ['cblas'], ['blas']]: 2121 try: 2122 c.link_executable(obj, os.path.join(tmpdir, "a.out"), 2123 libraries=libs, 2124 library_dirs=info['library_dirs'], 2125 extra_postargs=info.get('extra_link_args', [])) 2126 return libs 2127 except distutils.ccompiler.LinkError: 2128 pass 2129 finally: 2130 shutil.rmtree(tmpdir) 2131 return None 2132 2133 2134class openblas_info(blas_info): 2135 section = 'openblas' 2136 dir_env_var = 'OPENBLAS' 2137 _lib_names = ['openblas'] 2138 _require_symbols = [] 2139 notfounderror = BlasNotFoundError 2140 2141 @property 2142 def symbol_prefix(self): 2143 try: 2144 return self.cp.get(self.section, 'symbol_prefix') 2145 except NoOptionError: 2146 return '' 2147 2148 @property 2149 def symbol_suffix(self): 2150 try: 2151 return self.cp.get(self.section, 'symbol_suffix') 2152 except NoOptionError: 2153 return '' 2154 2155 def _calc_info(self): 2156 c = customized_ccompiler() 2157 2158 lib_dirs = self.get_lib_dirs() 2159 2160 # Prefer to use libraries over openblas_libs 2161 opt = self.get_option_single('openblas_libs', 'libraries') 2162 openblas_libs = self.get_libs(opt, self._lib_names) 2163 2164 info = self.check_libs(lib_dirs, openblas_libs, []) 2165 2166 if c.compiler_type == "msvc" and info is None: 2167 from numpy.distutils.fcompiler import new_fcompiler 2168 f = new_fcompiler(c_compiler=c) 2169 if f and f.compiler_type == 'gnu95': 2170 # Try gfortran-compatible library files 2171 info = self.check_msvc_gfortran_libs(lib_dirs, openblas_libs) 2172 # Skip lapack check, we'd need build_ext to do it 2173 skip_symbol_check = True 2174 elif info: 2175 skip_symbol_check = False 2176 info['language'] = 'c' 2177 2178 if info is None: 2179 return None 2180 2181 # Add extra info for OpenBLAS 2182 extra_info = self.calc_extra_info() 2183 dict_append(info, **extra_info) 2184 2185 if not (skip_symbol_check or self.check_symbols(info)): 2186 return None 2187 2188 info['define_macros'] = [('HAVE_CBLAS', None)] 2189 if self.symbol_prefix: 2190 info['define_macros'] += [('BLAS_SYMBOL_PREFIX', self.symbol_prefix)] 2191 if self.symbol_suffix: 2192 info['define_macros'] += [('BLAS_SYMBOL_SUFFIX', self.symbol_suffix)] 2193 2194 return info 2195 2196 def calc_info(self): 2197 info = self._calc_info() 2198 if info is not None: 2199 self.set_info(**info) 2200 2201 def check_msvc_gfortran_libs(self, library_dirs, libraries): 2202 # First, find the full path to each library directory 2203 library_paths = [] 2204 for library in libraries: 2205 for library_dir in library_dirs: 2206 # MinGW static ext will be .a 2207 fullpath = os.path.join(library_dir, library + '.a') 2208 if os.path.isfile(fullpath): 2209 library_paths.append(fullpath) 2210 break 2211 else: 2212 return None 2213 2214 # Generate numpy.distutils virtual static library file 2215 basename = self.__class__.__name__ 2216 tmpdir = os.path.join(os.getcwd(), 'build', basename) 2217 if not os.path.isdir(tmpdir): 2218 os.makedirs(tmpdir) 2219 2220 info = {'library_dirs': [tmpdir], 2221 'libraries': [basename], 2222 'language': 'f77'} 2223 2224 fake_lib_file = os.path.join(tmpdir, basename + '.fobjects') 2225 fake_clib_file = os.path.join(tmpdir, basename + '.cobjects') 2226 with open(fake_lib_file, 'w') as f: 2227 f.write("\n".join(library_paths)) 2228 with open(fake_clib_file, 'w') as f: 2229 pass 2230 2231 return info 2232 2233 def check_symbols(self, info): 2234 res = False 2235 c = customized_ccompiler() 2236 2237 tmpdir = tempfile.mkdtemp() 2238 2239 prototypes = "\n".join("void %s%s%s();" % (self.symbol_prefix, 2240 symbol_name, 2241 self.symbol_suffix) 2242 for symbol_name in self._require_symbols) 2243 calls = "\n".join("%s%s%s();" % (self.symbol_prefix, 2244 symbol_name, 2245 self.symbol_suffix) 2246 for symbol_name in self._require_symbols) 2247 s = textwrap.dedent("""\ 2248 %(prototypes)s 2249 int main(int argc, const char *argv[]) 2250 { 2251 %(calls)s 2252 return 0; 2253 }""") % dict(prototypes=prototypes, calls=calls) 2254 src = os.path.join(tmpdir, 'source.c') 2255 out = os.path.join(tmpdir, 'a.out') 2256 # Add the additional "extra" arguments 2257 try: 2258 extra_args = info['extra_link_args'] 2259 except Exception: 2260 extra_args = [] 2261 try: 2262 with open(src, 'wt') as f: 2263 f.write(s) 2264 obj = c.compile([src], output_dir=tmpdir) 2265 try: 2266 c.link_executable(obj, out, libraries=info['libraries'], 2267 library_dirs=info['library_dirs'], 2268 extra_postargs=extra_args) 2269 res = True 2270 except distutils.ccompiler.LinkError: 2271 res = False 2272 finally: 2273 shutil.rmtree(tmpdir) 2274 return res 2275 2276class openblas_lapack_info(openblas_info): 2277 section = 'openblas' 2278 dir_env_var = 'OPENBLAS' 2279 _lib_names = ['openblas'] 2280 _require_symbols = ['zungqr_'] 2281 notfounderror = BlasNotFoundError 2282 2283class openblas_clapack_info(openblas_lapack_info): 2284 _lib_names = ['openblas', 'lapack'] 2285 2286class openblas_ilp64_info(openblas_info): 2287 section = 'openblas_ilp64' 2288 dir_env_var = 'OPENBLAS_ILP64' 2289 _lib_names = ['openblas64'] 2290 _require_symbols = ['dgemm_', 'cblas_dgemm'] 2291 notfounderror = BlasILP64NotFoundError 2292 2293 def _calc_info(self): 2294 info = super()._calc_info() 2295 if info is not None: 2296 info['define_macros'] += [('HAVE_BLAS_ILP64', None)] 2297 return info 2298 2299class openblas_ilp64_lapack_info(openblas_ilp64_info): 2300 _require_symbols = ['dgemm_', 'cblas_dgemm', 'zungqr_', 'LAPACKE_zungqr'] 2301 2302 def _calc_info(self): 2303 info = super()._calc_info() 2304 if info: 2305 info['define_macros'] += [('HAVE_LAPACKE', None)] 2306 return info 2307 2308class openblas64__info(openblas_ilp64_info): 2309 # ILP64 Openblas, with default symbol suffix 2310 section = 'openblas64_' 2311 dir_env_var = 'OPENBLAS64_' 2312 _lib_names = ['openblas64_'] 2313 symbol_suffix = '64_' 2314 symbol_prefix = '' 2315 2316class openblas64__lapack_info(openblas_ilp64_lapack_info, openblas64__info): 2317 pass 2318 2319class blis_info(blas_info): 2320 section = 'blis' 2321 dir_env_var = 'BLIS' 2322 _lib_names = ['blis'] 2323 notfounderror = BlasNotFoundError 2324 2325 def calc_info(self): 2326 lib_dirs = self.get_lib_dirs() 2327 opt = self.get_option_single('blis_libs', 'libraries') 2328 blis_libs = self.get_libs(opt, self._lib_names) 2329 info = self.check_libs2(lib_dirs, blis_libs, []) 2330 if info is None: 2331 return 2332 2333 # Add include dirs 2334 incl_dirs = self.get_include_dirs() 2335 dict_append(info, 2336 language='c', 2337 define_macros=[('HAVE_CBLAS', None)], 2338 include_dirs=incl_dirs) 2339 self.set_info(**info) 2340 2341 2342class flame_info(system_info): 2343 """ Usage of libflame for LAPACK operations 2344 2345 This requires libflame to be compiled with lapack wrappers: 2346 2347 ./configure --enable-lapack2flame ... 2348 2349 Be aware that libflame 5.1.0 has some missing names in the shared library, so 2350 if you have problems, try the static flame library. 2351 """ 2352 section = 'flame' 2353 _lib_names = ['flame'] 2354 notfounderror = FlameNotFoundError 2355 2356 def check_embedded_lapack(self, info): 2357 """ libflame does not necessarily have a wrapper for fortran LAPACK, we need to check """ 2358 c = customized_ccompiler() 2359 2360 tmpdir = tempfile.mkdtemp() 2361 s = textwrap.dedent("""\ 2362 void zungqr_(); 2363 int main(int argc, const char *argv[]) 2364 { 2365 zungqr_(); 2366 return 0; 2367 }""") 2368 src = os.path.join(tmpdir, 'source.c') 2369 out = os.path.join(tmpdir, 'a.out') 2370 # Add the additional "extra" arguments 2371 extra_args = info.get('extra_link_args', []) 2372 try: 2373 with open(src, 'wt') as f: 2374 f.write(s) 2375 obj = c.compile([src], output_dir=tmpdir) 2376 try: 2377 c.link_executable(obj, out, libraries=info['libraries'], 2378 library_dirs=info['library_dirs'], 2379 extra_postargs=extra_args) 2380 return True 2381 except distutils.ccompiler.LinkError: 2382 return False 2383 finally: 2384 shutil.rmtree(tmpdir) 2385 2386 def calc_info(self): 2387 lib_dirs = self.get_lib_dirs() 2388 flame_libs = self.get_libs('libraries', self._lib_names) 2389 2390 info = self.check_libs2(lib_dirs, flame_libs, []) 2391 if info is None: 2392 return 2393 2394 if self.check_embedded_lapack(info): 2395 # check if the user has supplied all information required 2396 self.set_info(**info) 2397 else: 2398 # Try and get the BLAS lib to see if we can get it to work 2399 blas_info = get_info('blas_opt') 2400 if not blas_info: 2401 # since we already failed once, this ain't going to work either 2402 return 2403 2404 # Now we need to merge the two dictionaries 2405 for key in blas_info: 2406 if isinstance(blas_info[key], list): 2407 info[key] = info.get(key, []) + blas_info[key] 2408 elif isinstance(blas_info[key], tuple): 2409 info[key] = info.get(key, ()) + blas_info[key] 2410 else: 2411 info[key] = info.get(key, '') + blas_info[key] 2412 2413 # Now check again 2414 if self.check_embedded_lapack(info): 2415 self.set_info(**info) 2416 2417 2418class accelerate_info(system_info): 2419 section = 'accelerate' 2420 _lib_names = ['accelerate', 'veclib'] 2421 notfounderror = BlasNotFoundError 2422 2423 def calc_info(self): 2424 # Make possible to enable/disable from config file/env var 2425 libraries = os.environ.get('ACCELERATE') 2426 if libraries: 2427 libraries = [libraries] 2428 else: 2429 libraries = self.get_libs('libraries', self._lib_names) 2430 libraries = [lib.strip().lower() for lib in libraries] 2431 2432 if (sys.platform == 'darwin' and 2433 not os.getenv('_PYTHON_HOST_PLATFORM', None)): 2434 # Use the system BLAS from Accelerate or vecLib under OSX 2435 args = [] 2436 link_args = [] 2437 if get_platform()[-4:] == 'i386' or 'intel' in get_platform() or \ 2438 'x86_64' in get_platform() or \ 2439 'i386' in platform.platform(): 2440 intel = 1 2441 else: 2442 intel = 0 2443 if (os.path.exists('/System/Library/Frameworks' 2444 '/Accelerate.framework/') and 2445 'accelerate' in libraries): 2446 if intel: 2447 args.extend(['-msse3']) 2448 args.extend([ 2449 '-I/System/Library/Frameworks/vecLib.framework/Headers']) 2450 link_args.extend(['-Wl,-framework', '-Wl,Accelerate']) 2451 elif (os.path.exists('/System/Library/Frameworks' 2452 '/vecLib.framework/') and 2453 'veclib' in libraries): 2454 if intel: 2455 args.extend(['-msse3']) 2456 args.extend([ 2457 '-I/System/Library/Frameworks/vecLib.framework/Headers']) 2458 link_args.extend(['-Wl,-framework', '-Wl,vecLib']) 2459 2460 if args: 2461 self.set_info(extra_compile_args=args, 2462 extra_link_args=link_args, 2463 define_macros=[('NO_ATLAS_INFO', 3), 2464 ('HAVE_CBLAS', None)]) 2465 2466 return 2467 2468class blas_src_info(system_info): 2469 section = 'blas_src' 2470 dir_env_var = 'BLAS_SRC' 2471 notfounderror = BlasSrcNotFoundError 2472 2473 def get_paths(self, section, key): 2474 pre_dirs = system_info.get_paths(self, section, key) 2475 dirs = [] 2476 for d in pre_dirs: 2477 dirs.extend([d] + self.combine_paths(d, ['blas'])) 2478 return [d for d in dirs if os.path.isdir(d)] 2479 2480 def calc_info(self): 2481 src_dirs = self.get_src_dirs() 2482 src_dir = '' 2483 for d in src_dirs: 2484 if os.path.isfile(os.path.join(d, 'daxpy.f')): 2485 src_dir = d 2486 break 2487 if not src_dir: 2488 #XXX: Get sources from netlib. May be ask first. 2489 return 2490 blas1 = ''' 2491 caxpy csscal dnrm2 dzasum saxpy srotg zdotc ccopy cswap drot 2492 dznrm2 scasum srotm zdotu cdotc dasum drotg icamax scnrm2 2493 srotmg zdrot cdotu daxpy drotm idamax scopy sscal zdscal crotg 2494 dcabs1 drotmg isamax sdot sswap zrotg cscal dcopy dscal izamax 2495 snrm2 zaxpy zscal csrot ddot dswap sasum srot zcopy zswap 2496 scabs1 2497 ''' 2498 blas2 = ''' 2499 cgbmv chpmv ctrsv dsymv dtrsv sspr2 strmv zhemv ztpmv cgemv 2500 chpr dgbmv dsyr lsame ssymv strsv zher ztpsv cgerc chpr2 dgemv 2501 dsyr2 sgbmv ssyr xerbla zher2 ztrmv cgeru ctbmv dger dtbmv 2502 sgemv ssyr2 zgbmv zhpmv ztrsv chbmv ctbsv dsbmv dtbsv sger 2503 stbmv zgemv zhpr chemv ctpmv dspmv dtpmv ssbmv stbsv zgerc 2504 zhpr2 cher ctpsv dspr dtpsv sspmv stpmv zgeru ztbmv cher2 2505 ctrmv dspr2 dtrmv sspr stpsv zhbmv ztbsv 2506 ''' 2507 blas3 = ''' 2508 cgemm csymm ctrsm dsyrk sgemm strmm zhemm zsyr2k chemm csyr2k 2509 dgemm dtrmm ssymm strsm zher2k zsyrk cher2k csyrk dsymm dtrsm 2510 ssyr2k zherk ztrmm cherk ctrmm dsyr2k ssyrk zgemm zsymm ztrsm 2511 ''' 2512 sources = [os.path.join(src_dir, f + '.f') \ 2513 for f in (blas1 + blas2 + blas3).split()] 2514 #XXX: should we check here actual existence of source files? 2515 sources = [f for f in sources if os.path.isfile(f)] 2516 info = {'sources': sources, 'language': 'f77'} 2517 self.set_info(**info) 2518 2519 2520class x11_info(system_info): 2521 section = 'x11' 2522 notfounderror = X11NotFoundError 2523 _lib_names = ['X11'] 2524 2525 def __init__(self): 2526 system_info.__init__(self, 2527 default_lib_dirs=default_x11_lib_dirs, 2528 default_include_dirs=default_x11_include_dirs) 2529 2530 def calc_info(self): 2531 if sys.platform in ['win32']: 2532 return 2533 lib_dirs = self.get_lib_dirs() 2534 include_dirs = self.get_include_dirs() 2535 opt = self.get_option_single('x11_libs', 'libraries') 2536 x11_libs = self.get_libs(opt, self._lib_names) 2537 info = self.check_libs(lib_dirs, x11_libs, []) 2538 if info is None: 2539 return 2540 inc_dir = None 2541 for d in include_dirs: 2542 if self.combine_paths(d, 'X11/X.h'): 2543 inc_dir = d 2544 break 2545 if inc_dir is not None: 2546 dict_append(info, include_dirs=[inc_dir]) 2547 self.set_info(**info) 2548 2549 2550class _numpy_info(system_info): 2551 section = 'Numeric' 2552 modulename = 'Numeric' 2553 notfounderror = NumericNotFoundError 2554 2555 def __init__(self): 2556 include_dirs = [] 2557 try: 2558 module = __import__(self.modulename) 2559 prefix = [] 2560 for name in module.__file__.split(os.sep): 2561 if name == 'lib': 2562 break 2563 prefix.append(name) 2564 2565 # Ask numpy for its own include path before attempting 2566 # anything else 2567 try: 2568 include_dirs.append(getattr(module, 'get_include')()) 2569 except AttributeError: 2570 pass 2571 2572 include_dirs.append(sysconfig.get_path('include')) 2573 except ImportError: 2574 pass 2575 py_incl_dir = sysconfig.get_path('include') 2576 include_dirs.append(py_incl_dir) 2577 py_pincl_dir = sysconfig.get_path('platinclude') 2578 if py_pincl_dir not in include_dirs: 2579 include_dirs.append(py_pincl_dir) 2580 for d in default_include_dirs: 2581 d = os.path.join(d, os.path.basename(py_incl_dir)) 2582 if d not in include_dirs: 2583 include_dirs.append(d) 2584 system_info.__init__(self, 2585 default_lib_dirs=[], 2586 default_include_dirs=include_dirs) 2587 2588 def calc_info(self): 2589 try: 2590 module = __import__(self.modulename) 2591 except ImportError: 2592 return 2593 info = {} 2594 macros = [] 2595 for v in ['__version__', 'version']: 2596 vrs = getattr(module, v, None) 2597 if vrs is None: 2598 continue 2599 macros = [(self.modulename.upper() + '_VERSION', 2600 _c_string_literal(vrs)), 2601 (self.modulename.upper(), None)] 2602 break 2603 dict_append(info, define_macros=macros) 2604 include_dirs = self.get_include_dirs() 2605 inc_dir = None 2606 for d in include_dirs: 2607 if self.combine_paths(d, 2608 os.path.join(self.modulename, 2609 'arrayobject.h')): 2610 inc_dir = d 2611 break 2612 if inc_dir is not None: 2613 dict_append(info, include_dirs=[inc_dir]) 2614 if info: 2615 self.set_info(**info) 2616 return 2617 2618 2619class numarray_info(_numpy_info): 2620 section = 'numarray' 2621 modulename = 'numarray' 2622 2623 2624class Numeric_info(_numpy_info): 2625 section = 'Numeric' 2626 modulename = 'Numeric' 2627 2628 2629class numpy_info(_numpy_info): 2630 section = 'numpy' 2631 modulename = 'numpy' 2632 2633 2634class numerix_info(system_info): 2635 section = 'numerix' 2636 2637 def calc_info(self): 2638 which = None, None 2639 if os.getenv("NUMERIX"): 2640 which = os.getenv("NUMERIX"), "environment var" 2641 # If all the above fail, default to numpy. 2642 if which[0] is None: 2643 which = "numpy", "defaulted" 2644 try: 2645 import numpy # noqa: F401 2646 which = "numpy", "defaulted" 2647 except ImportError as e: 2648 msg1 = str(e) 2649 try: 2650 import Numeric # noqa: F401 2651 which = "numeric", "defaulted" 2652 except ImportError as e: 2653 msg2 = str(e) 2654 try: 2655 import numarray # noqa: F401 2656 which = "numarray", "defaulted" 2657 except ImportError as e: 2658 msg3 = str(e) 2659 log.info(msg1) 2660 log.info(msg2) 2661 log.info(msg3) 2662 which = which[0].strip().lower(), which[1] 2663 if which[0] not in ["numeric", "numarray", "numpy"]: 2664 raise ValueError("numerix selector must be either 'Numeric' " 2665 "or 'numarray' or 'numpy' but the value obtained" 2666 " from the %s was '%s'." % (which[1], which[0])) 2667 os.environ['NUMERIX'] = which[0] 2668 self.set_info(**get_info(which[0])) 2669 2670 2671class f2py_info(system_info): 2672 def calc_info(self): 2673 try: 2674 import numpy.f2py as f2py 2675 except ImportError: 2676 return 2677 f2py_dir = os.path.join(os.path.dirname(f2py.__file__), 'src') 2678 self.set_info(sources=[os.path.join(f2py_dir, 'fortranobject.c')], 2679 include_dirs=[f2py_dir]) 2680 return 2681 2682 2683class boost_python_info(system_info): 2684 section = 'boost_python' 2685 dir_env_var = 'BOOST' 2686 2687 def get_paths(self, section, key): 2688 pre_dirs = system_info.get_paths(self, section, key) 2689 dirs = [] 2690 for d in pre_dirs: 2691 dirs.extend([d] + self.combine_paths(d, ['boost*'])) 2692 return [d for d in dirs if os.path.isdir(d)] 2693 2694 def calc_info(self): 2695 src_dirs = self.get_src_dirs() 2696 src_dir = '' 2697 for d in src_dirs: 2698 if os.path.isfile(os.path.join(d, 'libs', 'python', 'src', 2699 'module.cpp')): 2700 src_dir = d 2701 break 2702 if not src_dir: 2703 return 2704 py_incl_dirs = [sysconfig.get_path('include')] 2705 py_pincl_dir = sysconfig.get_path('platinclude') 2706 if py_pincl_dir not in py_incl_dirs: 2707 py_incl_dirs.append(py_pincl_dir) 2708 srcs_dir = os.path.join(src_dir, 'libs', 'python', 'src') 2709 bpl_srcs = glob(os.path.join(srcs_dir, '*.cpp')) 2710 bpl_srcs += glob(os.path.join(srcs_dir, '*', '*.cpp')) 2711 info = {'libraries': [('boost_python_src', 2712 {'include_dirs': [src_dir] + py_incl_dirs, 2713 'sources':bpl_srcs} 2714 )], 2715 'include_dirs': [src_dir], 2716 } 2717 if info: 2718 self.set_info(**info) 2719 return 2720 2721 2722class agg2_info(system_info): 2723 section = 'agg2' 2724 dir_env_var = 'AGG2' 2725 2726 def get_paths(self, section, key): 2727 pre_dirs = system_info.get_paths(self, section, key) 2728 dirs = [] 2729 for d in pre_dirs: 2730 dirs.extend([d] + self.combine_paths(d, ['agg2*'])) 2731 return [d for d in dirs if os.path.isdir(d)] 2732 2733 def calc_info(self): 2734 src_dirs = self.get_src_dirs() 2735 src_dir = '' 2736 for d in src_dirs: 2737 if os.path.isfile(os.path.join(d, 'src', 'agg_affine_matrix.cpp')): 2738 src_dir = d 2739 break 2740 if not src_dir: 2741 return 2742 if sys.platform == 'win32': 2743 agg2_srcs = glob(os.path.join(src_dir, 'src', 'platform', 2744 'win32', 'agg_win32_bmp.cpp')) 2745 else: 2746 agg2_srcs = glob(os.path.join(src_dir, 'src', '*.cpp')) 2747 agg2_srcs += [os.path.join(src_dir, 'src', 'platform', 2748 'X11', 2749 'agg_platform_support.cpp')] 2750 2751 info = {'libraries': 2752 [('agg2_src', 2753 {'sources': agg2_srcs, 2754 'include_dirs': [os.path.join(src_dir, 'include')], 2755 } 2756 )], 2757 'include_dirs': [os.path.join(src_dir, 'include')], 2758 } 2759 if info: 2760 self.set_info(**info) 2761 return 2762 2763 2764class _pkg_config_info(system_info): 2765 section = None 2766 config_env_var = 'PKG_CONFIG' 2767 default_config_exe = 'pkg-config' 2768 append_config_exe = '' 2769 version_macro_name = None 2770 release_macro_name = None 2771 version_flag = '--modversion' 2772 cflags_flag = '--cflags' 2773 2774 def get_config_exe(self): 2775 if self.config_env_var in os.environ: 2776 return os.environ[self.config_env_var] 2777 return self.default_config_exe 2778 2779 def get_config_output(self, config_exe, option): 2780 cmd = config_exe + ' ' + self.append_config_exe + ' ' + option 2781 try: 2782 o = subprocess.check_output(cmd) 2783 except (OSError, subprocess.CalledProcessError): 2784 pass 2785 else: 2786 o = filepath_from_subprocess_output(o) 2787 return o 2788 2789 def calc_info(self): 2790 config_exe = find_executable(self.get_config_exe()) 2791 if not config_exe: 2792 log.warn('File not found: %s. Cannot determine %s info.' \ 2793 % (config_exe, self.section)) 2794 return 2795 info = {} 2796 macros = [] 2797 libraries = [] 2798 library_dirs = [] 2799 include_dirs = [] 2800 extra_link_args = [] 2801 extra_compile_args = [] 2802 version = self.get_config_output(config_exe, self.version_flag) 2803 if version: 2804 macros.append((self.__class__.__name__.split('.')[-1].upper(), 2805 _c_string_literal(version))) 2806 if self.version_macro_name: 2807 macros.append((self.version_macro_name + '_%s' 2808 % (version.replace('.', '_')), None)) 2809 if self.release_macro_name: 2810 release = self.get_config_output(config_exe, '--release') 2811 if release: 2812 macros.append((self.release_macro_name + '_%s' 2813 % (release.replace('.', '_')), None)) 2814 opts = self.get_config_output(config_exe, '--libs') 2815 if opts: 2816 for opt in opts.split(): 2817 if opt[:2] == '-l': 2818 libraries.append(opt[2:]) 2819 elif opt[:2] == '-L': 2820 library_dirs.append(opt[2:]) 2821 else: 2822 extra_link_args.append(opt) 2823 opts = self.get_config_output(config_exe, self.cflags_flag) 2824 if opts: 2825 for opt in opts.split(): 2826 if opt[:2] == '-I': 2827 include_dirs.append(opt[2:]) 2828 elif opt[:2] == '-D': 2829 if '=' in opt: 2830 n, v = opt[2:].split('=') 2831 macros.append((n, v)) 2832 else: 2833 macros.append((opt[2:], None)) 2834 else: 2835 extra_compile_args.append(opt) 2836 if macros: 2837 dict_append(info, define_macros=macros) 2838 if libraries: 2839 dict_append(info, libraries=libraries) 2840 if library_dirs: 2841 dict_append(info, library_dirs=library_dirs) 2842 if include_dirs: 2843 dict_append(info, include_dirs=include_dirs) 2844 if extra_link_args: 2845 dict_append(info, extra_link_args=extra_link_args) 2846 if extra_compile_args: 2847 dict_append(info, extra_compile_args=extra_compile_args) 2848 if info: 2849 self.set_info(**info) 2850 return 2851 2852 2853class wx_info(_pkg_config_info): 2854 section = 'wx' 2855 config_env_var = 'WX_CONFIG' 2856 default_config_exe = 'wx-config' 2857 append_config_exe = '' 2858 version_macro_name = 'WX_VERSION' 2859 release_macro_name = 'WX_RELEASE' 2860 version_flag = '--version' 2861 cflags_flag = '--cxxflags' 2862 2863 2864class gdk_pixbuf_xlib_2_info(_pkg_config_info): 2865 section = 'gdk_pixbuf_xlib_2' 2866 append_config_exe = 'gdk-pixbuf-xlib-2.0' 2867 version_macro_name = 'GDK_PIXBUF_XLIB_VERSION' 2868 2869 2870class gdk_pixbuf_2_info(_pkg_config_info): 2871 section = 'gdk_pixbuf_2' 2872 append_config_exe = 'gdk-pixbuf-2.0' 2873 version_macro_name = 'GDK_PIXBUF_VERSION' 2874 2875 2876class gdk_x11_2_info(_pkg_config_info): 2877 section = 'gdk_x11_2' 2878 append_config_exe = 'gdk-x11-2.0' 2879 version_macro_name = 'GDK_X11_VERSION' 2880 2881 2882class gdk_2_info(_pkg_config_info): 2883 section = 'gdk_2' 2884 append_config_exe = 'gdk-2.0' 2885 version_macro_name = 'GDK_VERSION' 2886 2887 2888class gdk_info(_pkg_config_info): 2889 section = 'gdk' 2890 append_config_exe = 'gdk' 2891 version_macro_name = 'GDK_VERSION' 2892 2893 2894class gtkp_x11_2_info(_pkg_config_info): 2895 section = 'gtkp_x11_2' 2896 append_config_exe = 'gtk+-x11-2.0' 2897 version_macro_name = 'GTK_X11_VERSION' 2898 2899 2900class gtkp_2_info(_pkg_config_info): 2901 section = 'gtkp_2' 2902 append_config_exe = 'gtk+-2.0' 2903 version_macro_name = 'GTK_VERSION' 2904 2905 2906class xft_info(_pkg_config_info): 2907 section = 'xft' 2908 append_config_exe = 'xft' 2909 version_macro_name = 'XFT_VERSION' 2910 2911 2912class freetype2_info(_pkg_config_info): 2913 section = 'freetype2' 2914 append_config_exe = 'freetype2' 2915 version_macro_name = 'FREETYPE2_VERSION' 2916 2917 2918class amd_info(system_info): 2919 section = 'amd' 2920 dir_env_var = 'AMD' 2921 _lib_names = ['amd'] 2922 2923 def calc_info(self): 2924 lib_dirs = self.get_lib_dirs() 2925 2926 opt = self.get_option_single('amd_libs', 'libraries') 2927 amd_libs = self.get_libs(opt, self._lib_names) 2928 info = self.check_libs(lib_dirs, amd_libs, []) 2929 if info is None: 2930 return 2931 2932 include_dirs = self.get_include_dirs() 2933 2934 inc_dir = None 2935 for d in include_dirs: 2936 p = self.combine_paths(d, 'amd.h') 2937 if p: 2938 inc_dir = os.path.dirname(p[0]) 2939 break 2940 if inc_dir is not None: 2941 dict_append(info, include_dirs=[inc_dir], 2942 define_macros=[('SCIPY_AMD_H', None)], 2943 swig_opts=['-I' + inc_dir]) 2944 2945 self.set_info(**info) 2946 return 2947 2948 2949class umfpack_info(system_info): 2950 section = 'umfpack' 2951 dir_env_var = 'UMFPACK' 2952 notfounderror = UmfpackNotFoundError 2953 _lib_names = ['umfpack'] 2954 2955 def calc_info(self): 2956 lib_dirs = self.get_lib_dirs() 2957 2958 opt = self.get_option_single('umfpack_libs', 'libraries') 2959 umfpack_libs = self.get_libs(opt, self._lib_names) 2960 info = self.check_libs(lib_dirs, umfpack_libs, []) 2961 if info is None: 2962 return 2963 2964 include_dirs = self.get_include_dirs() 2965 2966 inc_dir = None 2967 for d in include_dirs: 2968 p = self.combine_paths(d, ['', 'umfpack'], 'umfpack.h') 2969 if p: 2970 inc_dir = os.path.dirname(p[0]) 2971 break 2972 if inc_dir is not None: 2973 dict_append(info, include_dirs=[inc_dir], 2974 define_macros=[('SCIPY_UMFPACK_H', None)], 2975 swig_opts=['-I' + inc_dir]) 2976 2977 dict_append(info, **get_info('amd')) 2978 2979 self.set_info(**info) 2980 return 2981 2982 2983def combine_paths(*args, **kws): 2984 """ Return a list of existing paths composed by all combinations of 2985 items from arguments. 2986 """ 2987 r = [] 2988 for a in args: 2989 if not a: 2990 continue 2991 if is_string(a): 2992 a = [a] 2993 r.append(a) 2994 args = r 2995 if not args: 2996 return [] 2997 if len(args) == 1: 2998 result = reduce(lambda a, b: a + b, map(glob, args[0]), []) 2999 elif len(args) == 2: 3000 result = [] 3001 for a0 in args[0]: 3002 for a1 in args[1]: 3003 result.extend(glob(os.path.join(a0, a1))) 3004 else: 3005 result = combine_paths(*(combine_paths(args[0], args[1]) + args[2:])) 3006 log.debug('(paths: %s)', ','.join(result)) 3007 return result 3008 3009language_map = {'c': 0, 'c++': 1, 'f77': 2, 'f90': 3} 3010inv_language_map = {0: 'c', 1: 'c++', 2: 'f77', 3: 'f90'} 3011 3012 3013def dict_append(d, **kws): 3014 languages = [] 3015 for k, v in kws.items(): 3016 if k == 'language': 3017 languages.append(v) 3018 continue 3019 if k in d: 3020 if k in ['library_dirs', 'include_dirs', 3021 'extra_compile_args', 'extra_link_args', 3022 'runtime_library_dirs', 'define_macros']: 3023 [d[k].append(vv) for vv in v if vv not in d[k]] 3024 else: 3025 d[k].extend(v) 3026 else: 3027 d[k] = v 3028 if languages: 3029 l = inv_language_map[max([language_map.get(l, 0) for l in languages])] 3030 d['language'] = l 3031 return 3032 3033 3034def parseCmdLine(argv=(None,)): 3035 import optparse 3036 parser = optparse.OptionParser("usage: %prog [-v] [info objs]") 3037 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', 3038 default=False, 3039 help='be verbose and print more messages') 3040 3041 opts, args = parser.parse_args(args=argv[1:]) 3042 return opts, args 3043 3044 3045def show_all(argv=None): 3046 import inspect 3047 if argv is None: 3048 argv = sys.argv 3049 opts, args = parseCmdLine(argv) 3050 if opts.verbose: 3051 log.set_threshold(log.DEBUG) 3052 else: 3053 log.set_threshold(log.INFO) 3054 show_only = [] 3055 for n in args: 3056 if n[-5:] != '_info': 3057 n = n + '_info' 3058 show_only.append(n) 3059 show_all = not show_only 3060 _gdict_ = globals().copy() 3061 for name, c in _gdict_.items(): 3062 if not inspect.isclass(c): 3063 continue 3064 if not issubclass(c, system_info) or c is system_info: 3065 continue 3066 if not show_all: 3067 if name not in show_only: 3068 continue 3069 del show_only[show_only.index(name)] 3070 conf = c() 3071 conf.verbosity = 2 3072 # FIXME: r not used 3073 r = conf.get_info() 3074 if show_only: 3075 log.info('Info classes not defined: %s', ','.join(show_only)) 3076 3077if __name__ == "__main__": 3078 show_all() 3079