comparison DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/distutils/system_info.py @ 87:2a2c65a20a8b

Add Python libs and headers
author Chris Cannam
date Wed, 25 Feb 2015 14:05:22 +0000
parents
children
comparison
equal deleted inserted replaced
86:413a9d26189e 87:2a2c65a20a8b
1 #!/bin/env python
2 """
3 This file defines a set of system_info classes for getting
4 information about various resources (libraries, library directories,
5 include directories, etc.) in the system. Currently, the following
6 classes are available:
7
8 atlas_info
9 atlas_threads_info
10 atlas_blas_info
11 atlas_blas_threads_info
12 lapack_atlas_info
13 blas_info
14 lapack_info
15 openblas_info
16 blas_opt_info # usage recommended
17 lapack_opt_info # usage recommended
18 fftw_info,dfftw_info,sfftw_info
19 fftw_threads_info,dfftw_threads_info,sfftw_threads_info
20 djbfft_info
21 x11_info
22 lapack_src_info
23 blas_src_info
24 numpy_info
25 numarray_info
26 numpy_info
27 boost_python_info
28 agg2_info
29 wx_info
30 gdk_pixbuf_xlib_2_info
31 gdk_pixbuf_2_info
32 gdk_x11_2_info
33 gtkp_x11_2_info
34 gtkp_2_info
35 xft_info
36 freetype2_info
37 umfpack_info
38
39 Usage:
40 info_dict = get_info(<name>)
41 where <name> is a string 'atlas','x11','fftw','lapack','blas',
42 'lapack_src', 'blas_src', etc. For a complete list of allowed names,
43 see the definition of get_info() function below.
44
45 Returned info_dict is a dictionary which is compatible with
46 distutils.setup keyword arguments. If info_dict == {}, then the
47 asked resource is not available (system_info could not find it).
48
49 Several *_info classes specify an environment variable to specify
50 the locations of software. When setting the corresponding environment
51 variable to 'None' then the software will be ignored, even when it
52 is available in system.
53
54 Global parameters:
55 system_info.search_static_first - search static libraries (.a)
56 in precedence to shared ones (.so, .sl) if enabled.
57 system_info.verbosity - output the results to stdout if enabled.
58
59 The file 'site.cfg' is looked for in
60
61 1) Directory of main setup.py file being run.
62 2) Home directory of user running the setup.py file as ~/.numpy-site.cfg
63 3) System wide directory (location of this file...)
64
65 The first one found is used to get system configuration options The
66 format is that used by ConfigParser (i.e., Windows .INI style). The
67 section ALL has options that are the default for each section. The
68 available sections are fftw, atlas, and x11. Appropiate defaults are
69 used if nothing is specified.
70
71 The order of finding the locations of resources is the following:
72 1. environment variable
73 2. section in site.cfg
74 3. ALL section in site.cfg
75 Only the first complete match is returned.
76
77 Example:
78 ----------
79 [ALL]
80 library_dirs = /usr/lib:/usr/local/lib:/opt/lib
81 include_dirs = /usr/include:/usr/local/include:/opt/include
82 src_dirs = /usr/local/src:/opt/src
83 # search static libraries (.a) in preference to shared ones (.so)
84 search_static_first = 0
85
86 [fftw]
87 fftw_libs = rfftw, fftw
88 fftw_opt_libs = rfftw_threaded, fftw_threaded
89 # if the above aren't found, look for {s,d}fftw_libs and {s,d}fftw_opt_libs
90
91 [atlas]
92 library_dirs = /usr/lib/3dnow:/usr/lib/3dnow/atlas
93 # for overriding the names of the atlas libraries
94 atlas_libs = lapack, f77blas, cblas, atlas
95
96 [x11]
97 library_dirs = /usr/X11R6/lib
98 include_dirs = /usr/X11R6/include
99 ----------
100
101 Authors:
102 Pearu Peterson <pearu@cens.ioc.ee>, February 2002
103 David M. Cooke <cookedm@physics.mcmaster.ca>, April 2002
104
105 Copyright 2002 Pearu Peterson all rights reserved,
106 Pearu Peterson <pearu@cens.ioc.ee>
107 Permission to use, modify, and distribute this software is given under the
108 terms of the NumPy (BSD style) license. See LICENSE.txt that came with
109 this distribution for specifics.
110
111 NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
112
113 """
114 from __future__ import division, absolute_import, print_function
115
116 import sys
117 import os
118 import re
119 import copy
120 import warnings
121 from glob import glob
122 from functools import reduce
123 if sys.version_info[0] < 3:
124 from ConfigParser import NoOptionError, ConfigParser
125 else:
126 from configparser import NoOptionError, ConfigParser
127
128 from distutils.errors import DistutilsError
129 from distutils.dist import Distribution
130 import distutils.sysconfig
131 from distutils import log
132 from distutils.util import get_platform
133
134 from numpy.distutils.exec_command import \
135 find_executable, exec_command, get_pythonexe
136 from numpy.distutils.misc_util import is_sequence, is_string, \
137 get_shared_lib_extension
138 from numpy.distutils.command.config import config as cmd_config
139 from numpy.distutils.compat import get_exception
140 import distutils.ccompiler
141 import tempfile
142 import shutil
143
144
145 # Determine number of bits
146 import platform
147 _bits = {'32bit': 32, '64bit': 64}
148 platform_bits = _bits[platform.architecture()[0]]
149
150
151 def libpaths(paths, bits):
152 """Return a list of library paths valid on 32 or 64 bit systems.
153
154 Inputs:
155 paths : sequence
156 A sequence of strings (typically paths)
157 bits : int
158 An integer, the only valid values are 32 or 64. A ValueError exception
159 is raised otherwise.
160
161 Examples:
162
163 Consider a list of directories
164 >>> paths = ['/usr/X11R6/lib','/usr/X11/lib','/usr/lib']
165
166 For a 32-bit platform, this is already valid:
167 >>> np.distutils.system_info.libpaths(paths,32)
168 ['/usr/X11R6/lib', '/usr/X11/lib', '/usr/lib']
169
170 On 64 bits, we prepend the '64' postfix
171 >>> np.distutils.system_info.libpaths(paths,64)
172 ['/usr/X11R6/lib64', '/usr/X11R6/lib', '/usr/X11/lib64', '/usr/X11/lib',
173 '/usr/lib64', '/usr/lib']
174 """
175 if bits not in (32, 64):
176 raise ValueError("Invalid bit size in libpaths: 32 or 64 only")
177
178 # Handle 32bit case
179 if bits == 32:
180 return paths
181
182 # Handle 64bit case
183 out = []
184 for p in paths:
185 out.extend([p + '64', p])
186
187 return out
188
189
190 if sys.platform == 'win32':
191 default_lib_dirs = ['C:\\',
192 os.path.join(distutils.sysconfig.EXEC_PREFIX,
193 'libs')]
194 default_include_dirs = []
195 default_src_dirs = ['.']
196 default_x11_lib_dirs = []
197 default_x11_include_dirs = []
198 else:
199 default_lib_dirs = libpaths(['/usr/local/lib', '/opt/lib', '/usr/lib',
200 '/opt/local/lib', '/sw/lib'], platform_bits)
201 default_include_dirs = ['/usr/local/include',
202 '/opt/include', '/usr/include',
203 # path of umfpack under macports
204 '/opt/local/include/ufsparse',
205 '/opt/local/include', '/sw/include',
206 '/usr/include/suitesparse']
207 default_src_dirs = ['.', '/usr/local/src', '/opt/src', '/sw/src']
208
209 default_x11_lib_dirs = libpaths(['/usr/X11R6/lib', '/usr/X11/lib',
210 '/usr/lib'], platform_bits)
211 default_x11_include_dirs = ['/usr/X11R6/include', '/usr/X11/include',
212 '/usr/include']
213
214 if os.path.exists('/usr/lib/X11'):
215 globbed_x11_dir = glob('/usr/lib/*/libX11.so')
216 if globbed_x11_dir:
217 x11_so_dir = os.path.split(globbed_x11_dir[0])[0]
218 default_x11_lib_dirs.extend([x11_so_dir, '/usr/lib/X11'])
219 default_x11_include_dirs.extend(['/usr/lib/X11/include',
220 '/usr/include/X11'])
221
222 import subprocess as sp
223 tmp = None
224 try:
225 # Explicitly open/close file to avoid ResourceWarning when
226 # tests are run in debug mode Python 3.
227 tmp = open(os.devnull, 'w')
228 p = sp.Popen(["gcc", "-print-multiarch"], stdout=sp.PIPE,
229 stderr=tmp)
230 except (OSError, DistutilsError):
231 # OSError if gcc is not installed, or SandboxViolation (DistutilsError
232 # subclass) if an old setuptools bug is triggered (see gh-3160).
233 pass
234 else:
235 triplet = str(p.communicate()[0].decode().strip())
236 if p.returncode == 0:
237 # gcc supports the "-print-multiarch" option
238 default_x11_lib_dirs += [os.path.join("/usr/lib/", triplet)]
239 default_lib_dirs += [os.path.join("/usr/lib/", triplet)]
240 finally:
241 if tmp is not None:
242 tmp.close()
243
244 if os.path.join(sys.prefix, 'lib') not in default_lib_dirs:
245 default_lib_dirs.insert(0, os.path.join(sys.prefix, 'lib'))
246 default_include_dirs.append(os.path.join(sys.prefix, 'include'))
247 default_src_dirs.append(os.path.join(sys.prefix, 'src'))
248
249 default_lib_dirs = [_m for _m in default_lib_dirs if os.path.isdir(_m)]
250 default_include_dirs = [_m for _m in default_include_dirs if os.path.isdir(_m)]
251 default_src_dirs = [_m for _m in default_src_dirs if os.path.isdir(_m)]
252
253 so_ext = get_shared_lib_extension()
254
255
256 def get_standard_file(fname):
257 """Returns a list of files named 'fname' from
258 1) System-wide directory (directory-location of this module)
259 2) Users HOME directory (os.environ['HOME'])
260 3) Local directory
261 """
262 # System-wide file
263 filenames = []
264 try:
265 f = __file__
266 except NameError:
267 f = sys.argv[0]
268 else:
269 sysfile = os.path.join(os.path.split(os.path.abspath(f))[0],
270 fname)
271 if os.path.isfile(sysfile):
272 filenames.append(sysfile)
273
274 # Home directory
275 # And look for the user config file
276 try:
277 f = os.path.expanduser('~')
278 except KeyError:
279 pass
280 else:
281 user_file = os.path.join(f, fname)
282 if os.path.isfile(user_file):
283 filenames.append(user_file)
284
285 # Local file
286 if os.path.isfile(fname):
287 filenames.append(os.path.abspath(fname))
288
289 return filenames
290
291
292 def get_info(name, notfound_action=0):
293 """
294 notfound_action:
295 0 - do nothing
296 1 - display warning message
297 2 - raise error
298 """
299 cl = {'atlas': atlas_info, # use lapack_opt or blas_opt instead
300 'atlas_threads': atlas_threads_info, # ditto
301 'atlas_blas': atlas_blas_info,
302 'atlas_blas_threads': atlas_blas_threads_info,
303 'lapack_atlas': lapack_atlas_info, # use lapack_opt instead
304 'lapack_atlas_threads': lapack_atlas_threads_info, # ditto
305 'mkl': mkl_info,
306 # openblas which may or may not have embedded lapack
307 'openblas': openblas_info, # use blas_opt instead
308 # openblas with embedded lapack
309 'openblas_lapack': openblas_lapack_info, # use blas_opt instead
310 'lapack_mkl': lapack_mkl_info, # use lapack_opt instead
311 'blas_mkl': blas_mkl_info, # use blas_opt instead
312 'x11': x11_info,
313 'fft_opt': fft_opt_info,
314 'fftw': fftw_info,
315 'fftw2': fftw2_info,
316 'fftw3': fftw3_info,
317 'dfftw': dfftw_info,
318 'sfftw': sfftw_info,
319 'fftw_threads': fftw_threads_info,
320 'dfftw_threads': dfftw_threads_info,
321 'sfftw_threads': sfftw_threads_info,
322 'djbfft': djbfft_info,
323 'blas': blas_info, # use blas_opt instead
324 'lapack': lapack_info, # use lapack_opt instead
325 'lapack_src': lapack_src_info,
326 'blas_src': blas_src_info,
327 'numpy': numpy_info,
328 'f2py': f2py_info,
329 'Numeric': Numeric_info,
330 'numeric': Numeric_info,
331 'numarray': numarray_info,
332 'numerix': numerix_info,
333 'lapack_opt': lapack_opt_info,
334 'blas_opt': blas_opt_info,
335 'boost_python': boost_python_info,
336 'agg2': agg2_info,
337 'wx': wx_info,
338 'gdk_pixbuf_xlib_2': gdk_pixbuf_xlib_2_info,
339 'gdk-pixbuf-xlib-2.0': gdk_pixbuf_xlib_2_info,
340 'gdk_pixbuf_2': gdk_pixbuf_2_info,
341 'gdk-pixbuf-2.0': gdk_pixbuf_2_info,
342 'gdk': gdk_info,
343 'gdk_2': gdk_2_info,
344 'gdk-2.0': gdk_2_info,
345 'gdk_x11_2': gdk_x11_2_info,
346 'gdk-x11-2.0': gdk_x11_2_info,
347 'gtkp_x11_2': gtkp_x11_2_info,
348 'gtk+-x11-2.0': gtkp_x11_2_info,
349 'gtkp_2': gtkp_2_info,
350 'gtk+-2.0': gtkp_2_info,
351 'xft': xft_info,
352 'freetype2': freetype2_info,
353 'umfpack': umfpack_info,
354 'amd': amd_info,
355 }.get(name.lower(), system_info)
356 return cl().get_info(notfound_action)
357
358
359 class NotFoundError(DistutilsError):
360 """Some third-party program or library is not found."""
361
362
363 class AtlasNotFoundError(NotFoundError):
364 """
365 Atlas (http://math-atlas.sourceforge.net/) libraries not found.
366 Directories to search for the libraries can be specified in the
367 numpy/distutils/site.cfg file (section [atlas]) or by setting
368 the ATLAS environment variable."""
369
370
371 class LapackNotFoundError(NotFoundError):
372 """
373 Lapack (http://www.netlib.org/lapack/) libraries not found.
374 Directories to search for the libraries can be specified in the
375 numpy/distutils/site.cfg file (section [lapack]) or by setting
376 the LAPACK environment variable."""
377
378
379 class LapackSrcNotFoundError(LapackNotFoundError):
380 """
381 Lapack (http://www.netlib.org/lapack/) sources not found.
382 Directories to search for the sources can be specified in the
383 numpy/distutils/site.cfg file (section [lapack_src]) or by setting
384 the LAPACK_SRC environment variable."""
385
386
387 class BlasNotFoundError(NotFoundError):
388 """
389 Blas (http://www.netlib.org/blas/) libraries not found.
390 Directories to search for the libraries can be specified in the
391 numpy/distutils/site.cfg file (section [blas]) or by setting
392 the BLAS environment variable."""
393
394
395 class BlasSrcNotFoundError(BlasNotFoundError):
396 """
397 Blas (http://www.netlib.org/blas/) sources not found.
398 Directories to search for the sources can be specified in the
399 numpy/distutils/site.cfg file (section [blas_src]) or by setting
400 the BLAS_SRC environment variable."""
401
402
403 class FFTWNotFoundError(NotFoundError):
404 """
405 FFTW (http://www.fftw.org/) libraries not found.
406 Directories to search for the libraries can be specified in the
407 numpy/distutils/site.cfg file (section [fftw]) or by setting
408 the FFTW environment variable."""
409
410
411 class DJBFFTNotFoundError(NotFoundError):
412 """
413 DJBFFT (http://cr.yp.to/djbfft.html) libraries not found.
414 Directories to search for the libraries can be specified in the
415 numpy/distutils/site.cfg file (section [djbfft]) or by setting
416 the DJBFFT environment variable."""
417
418
419 class NumericNotFoundError(NotFoundError):
420 """
421 Numeric (http://www.numpy.org/) module not found.
422 Get it from above location, install it, and retry setup.py."""
423
424
425 class X11NotFoundError(NotFoundError):
426 """X11 libraries not found."""
427
428
429 class UmfpackNotFoundError(NotFoundError):
430 """
431 UMFPACK sparse solver (http://www.cise.ufl.edu/research/sparse/umfpack/)
432 not found. Directories to search for the libraries can be specified in the
433 numpy/distutils/site.cfg file (section [umfpack]) or by setting
434 the UMFPACK environment variable."""
435
436
437 class system_info:
438
439 """ get_info() is the only public method. Don't use others.
440 """
441 section = 'ALL'
442 dir_env_var = None
443 search_static_first = 0 # XXX: disabled by default, may disappear in
444 # future unless it is proved to be useful.
445 verbosity = 1
446 saved_results = {}
447
448 notfounderror = NotFoundError
449
450 def __init__(self,
451 default_lib_dirs=default_lib_dirs,
452 default_include_dirs=default_include_dirs,
453 verbosity=1,
454 ):
455 self.__class__.info = {}
456 self.local_prefixes = []
457 defaults = {}
458 defaults['library_dirs'] = os.pathsep.join(default_lib_dirs)
459 defaults['include_dirs'] = os.pathsep.join(default_include_dirs)
460 defaults['src_dirs'] = os.pathsep.join(default_src_dirs)
461 defaults['search_static_first'] = str(self.search_static_first)
462 self.cp = ConfigParser(defaults)
463 self.files = []
464 self.files.extend(get_standard_file('.numpy-site.cfg'))
465 self.files.extend(get_standard_file('site.cfg'))
466 self.parse_config_files()
467 if self.section is not None:
468 self.search_static_first = self.cp.getboolean(
469 self.section, 'search_static_first')
470 assert isinstance(self.search_static_first, int)
471
472 def parse_config_files(self):
473 self.cp.read(self.files)
474 if not self.cp.has_section(self.section):
475 if self.section is not None:
476 self.cp.add_section(self.section)
477
478 def calc_libraries_info(self):
479 libs = self.get_libraries()
480 dirs = self.get_lib_dirs()
481 info = {}
482 for lib in libs:
483 i = self.check_libs(dirs, [lib])
484 if i is not None:
485 dict_append(info, **i)
486 else:
487 log.info('Library %s was not found. Ignoring' % (lib))
488 return info
489
490 def set_info(self, **info):
491 if info:
492 lib_info = self.calc_libraries_info()
493 dict_append(info, **lib_info)
494 self.saved_results[self.__class__.__name__] = info
495
496 def has_info(self):
497 return self.__class__.__name__ in self.saved_results
498
499 def get_info(self, notfound_action=0):
500 """ Return a dictonary with items that are compatible
501 with numpy.distutils.setup keyword arguments.
502 """
503 flag = 0
504 if not self.has_info():
505 flag = 1
506 log.info(self.__class__.__name__ + ':')
507 if hasattr(self, 'calc_info'):
508 self.calc_info()
509 if notfound_action:
510 if not self.has_info():
511 if notfound_action == 1:
512 warnings.warn(self.notfounderror.__doc__)
513 elif notfound_action == 2:
514 raise self.notfounderror(self.notfounderror.__doc__)
515 else:
516 raise ValueError(repr(notfound_action))
517
518 if not self.has_info():
519 log.info(' NOT AVAILABLE')
520 self.set_info()
521 else:
522 log.info(' FOUND:')
523
524 res = self.saved_results.get(self.__class__.__name__)
525 if self.verbosity > 0 and flag:
526 for k, v in res.items():
527 v = str(v)
528 if k in ['sources', 'libraries'] and len(v) > 270:
529 v = v[:120] + '...\n...\n...' + v[-120:]
530 log.info(' %s = %s', k, v)
531 log.info('')
532
533 return copy.deepcopy(res)
534
535 def get_paths(self, section, key):
536 dirs = self.cp.get(section, key).split(os.pathsep)
537 env_var = self.dir_env_var
538 if env_var:
539 if is_sequence(env_var):
540 e0 = env_var[-1]
541 for e in env_var:
542 if e in os.environ:
543 e0 = e
544 break
545 if not env_var[0] == e0:
546 log.info('Setting %s=%s' % (env_var[0], e0))
547 env_var = e0
548 if env_var and env_var in os.environ:
549 d = os.environ[env_var]
550 if d == 'None':
551 log.info('Disabled %s: %s',
552 self.__class__.__name__, '(%s is None)'
553 % (env_var,))
554 return []
555 if os.path.isfile(d):
556 dirs = [os.path.dirname(d)] + dirs
557 l = getattr(self, '_lib_names', [])
558 if len(l) == 1:
559 b = os.path.basename(d)
560 b = os.path.splitext(b)[0]
561 if b[:3] == 'lib':
562 log.info('Replacing _lib_names[0]==%r with %r' \
563 % (self._lib_names[0], b[3:]))
564 self._lib_names[0] = b[3:]
565 else:
566 ds = d.split(os.pathsep)
567 ds2 = []
568 for d in ds:
569 if os.path.isdir(d):
570 ds2.append(d)
571 for dd in ['include', 'lib']:
572 d1 = os.path.join(d, dd)
573 if os.path.isdir(d1):
574 ds2.append(d1)
575 dirs = ds2 + dirs
576 default_dirs = self.cp.get(self.section, key).split(os.pathsep)
577 dirs.extend(default_dirs)
578 ret = []
579 for d in dirs:
580 if not os.path.isdir(d):
581 warnings.warn('Specified path %s is invalid.' % d)
582 continue
583
584 if d not in ret:
585 ret.append(d)
586
587 log.debug('( %s = %s )', key, ':'.join(ret))
588 return ret
589
590 def get_lib_dirs(self, key='library_dirs'):
591 return self.get_paths(self.section, key)
592
593 def get_include_dirs(self, key='include_dirs'):
594 return self.get_paths(self.section, key)
595
596 def get_src_dirs(self, key='src_dirs'):
597 return self.get_paths(self.section, key)
598
599 def get_libs(self, key, default):
600 try:
601 libs = self.cp.get(self.section, key)
602 except NoOptionError:
603 if not default:
604 return []
605 if is_string(default):
606 return [default]
607 return default
608 return [b for b in [a.strip() for a in libs.split(',')] if b]
609
610 def get_libraries(self, key='libraries'):
611 return self.get_libs(key, '')
612
613 def library_extensions(self):
614 static_exts = ['.a']
615 if sys.platform == 'win32':
616 static_exts.append('.lib') # .lib is used by MSVC
617 if self.search_static_first:
618 exts = static_exts + [so_ext]
619 else:
620 exts = [so_ext] + static_exts
621 if sys.platform == 'cygwin':
622 exts.append('.dll.a')
623 if sys.platform == 'darwin':
624 exts.append('.dylib')
625 # Debian and Ubuntu added a g3f suffix to shared library to deal with
626 # g77 -> gfortran ABI transition
627 # XXX: disabled, it hides more problem than it solves.
628 #if sys.platform[:5] == 'linux':
629 # exts.append('.so.3gf')
630 return exts
631
632 def check_libs(self, lib_dirs, libs, opt_libs=[]):
633 """If static or shared libraries are available then return
634 their info dictionary.
635
636 Checks for all libraries as shared libraries first, then
637 static (or vice versa if self.search_static_first is True).
638 """
639 exts = self.library_extensions()
640 info = None
641 for ext in exts:
642 info = self._check_libs(lib_dirs, libs, opt_libs, [ext])
643 if info is not None:
644 break
645 if not info:
646 log.info(' libraries %s not found in %s', ','.join(libs),
647 lib_dirs)
648 return info
649
650 def check_libs2(self, lib_dirs, libs, opt_libs=[]):
651 """If static or shared libraries are available then return
652 their info dictionary.
653
654 Checks each library for shared or static.
655 """
656 exts = self.library_extensions()
657 info = self._check_libs(lib_dirs, libs, opt_libs, exts)
658 if not info:
659 log.info(' libraries %s not found in %s', ','.join(libs),
660 lib_dirs)
661 return info
662
663 def _lib_list(self, lib_dir, libs, exts):
664 assert is_string(lib_dir)
665 liblist = []
666 # under windows first try without 'lib' prefix
667 if sys.platform == 'win32':
668 lib_prefixes = ['', 'lib']
669 else:
670 lib_prefixes = ['lib']
671 # for each library name, see if we can find a file for it.
672 for l in libs:
673 for ext in exts:
674 for prefix in lib_prefixes:
675 p = self.combine_paths(lib_dir, prefix + l + ext)
676 if p:
677 break
678 if p:
679 assert len(p) == 1
680 # ??? splitext on p[0] would do this for cygwin
681 # doesn't seem correct
682 if ext == '.dll.a':
683 l += '.dll'
684 liblist.append(l)
685 break
686 return liblist
687
688 def _check_libs(self, lib_dirs, libs, opt_libs, exts):
689 """Find mandatory and optional libs in expected paths.
690
691 Missing optional libraries are silently forgotten.
692 """
693 # First, try to find the mandatory libraries
694 if is_sequence(lib_dirs):
695 found_libs, found_dirs = [], []
696 for dir_ in lib_dirs:
697 found_libs1 = self._lib_list(dir_, libs, exts)
698 # It's possible that we'll find the same library in multiple
699 # directories. It's also possible that we'll find some
700 # libraries on in directory, and some in another. So the
701 # obvious thing would be to use a set instead of a list, but I
702 # don't know if preserving order matters (does it?).
703 for found_lib in found_libs1:
704 if found_lib not in found_libs:
705 found_libs.append(found_lib)
706 if dir_ not in found_dirs:
707 found_dirs.append(dir_)
708 else:
709 found_libs = self._lib_list(lib_dirs, libs, exts)
710 found_dirs = [lib_dirs]
711 if len(found_libs) > 0 and len(found_libs) == len(libs):
712 info = {'libraries': found_libs, 'library_dirs': found_dirs}
713 # Now, check for optional libraries
714 if is_sequence(lib_dirs):
715 for dir_ in lib_dirs:
716 opt_found_libs = self._lib_list(dir_, opt_libs, exts)
717 if opt_found_libs:
718 if dir_ not in found_dirs:
719 found_dirs.extend(dir_)
720 found_libs.extend(opt_found_libs)
721 else:
722 opt_found_libs = self._lib_list(lib_dirs, opt_libs, exts)
723 if opt_found_libs:
724 found_libs.extend(opt_found_libs)
725 return info
726 else:
727 return None
728
729 def combine_paths(self, *args):
730 """Return a list of existing paths composed by all combinations
731 of items from the arguments.
732 """
733 return combine_paths(*args, **{'verbosity': self.verbosity})
734
735
736 class fft_opt_info(system_info):
737
738 def calc_info(self):
739 info = {}
740 fftw_info = get_info('fftw3') or get_info('fftw2') or get_info('dfftw')
741 djbfft_info = get_info('djbfft')
742 if fftw_info:
743 dict_append(info, **fftw_info)
744 if djbfft_info:
745 dict_append(info, **djbfft_info)
746 self.set_info(**info)
747 return
748
749
750 class fftw_info(system_info):
751 #variables to override
752 section = 'fftw'
753 dir_env_var = 'FFTW'
754 notfounderror = FFTWNotFoundError
755 ver_info = [{'name':'fftw3',
756 'libs':['fftw3'],
757 'includes':['fftw3.h'],
758 'macros':[('SCIPY_FFTW3_H', None)]},
759 {'name':'fftw2',
760 'libs':['rfftw', 'fftw'],
761 'includes':['fftw.h', 'rfftw.h'],
762 'macros':[('SCIPY_FFTW_H', None)]}]
763
764 def calc_ver_info(self, ver_param):
765 """Returns True on successful version detection, else False"""
766 lib_dirs = self.get_lib_dirs()
767 incl_dirs = self.get_include_dirs()
768 incl_dir = None
769 libs = self.get_libs(self.section + '_libs', ver_param['libs'])
770 info = self.check_libs(lib_dirs, libs)
771 if info is not None:
772 flag = 0
773 for d in incl_dirs:
774 if len(self.combine_paths(d, ver_param['includes'])) \
775 == len(ver_param['includes']):
776 dict_append(info, include_dirs=[d])
777 flag = 1
778 incl_dirs = [d]
779 break
780 if flag:
781 dict_append(info, define_macros=ver_param['macros'])
782 else:
783 info = None
784 if info is not None:
785 self.set_info(**info)
786 return True
787 else:
788 log.info(' %s not found' % (ver_param['name']))
789 return False
790
791 def calc_info(self):
792 for i in self.ver_info:
793 if self.calc_ver_info(i):
794 break
795
796
797 class fftw2_info(fftw_info):
798 #variables to override
799 section = 'fftw'
800 dir_env_var = 'FFTW'
801 notfounderror = FFTWNotFoundError
802 ver_info = [{'name':'fftw2',
803 'libs':['rfftw', 'fftw'],
804 'includes':['fftw.h', 'rfftw.h'],
805 'macros':[('SCIPY_FFTW_H', None)]}
806 ]
807
808
809 class fftw3_info(fftw_info):
810 #variables to override
811 section = 'fftw3'
812 dir_env_var = 'FFTW3'
813 notfounderror = FFTWNotFoundError
814 ver_info = [{'name':'fftw3',
815 'libs':['fftw3'],
816 'includes':['fftw3.h'],
817 'macros':[('SCIPY_FFTW3_H', None)]},
818 ]
819
820
821 class dfftw_info(fftw_info):
822 section = 'fftw'
823 dir_env_var = 'FFTW'
824 ver_info = [{'name':'dfftw',
825 'libs':['drfftw', 'dfftw'],
826 'includes':['dfftw.h', 'drfftw.h'],
827 'macros':[('SCIPY_DFFTW_H', None)]}]
828
829
830 class sfftw_info(fftw_info):
831 section = 'fftw'
832 dir_env_var = 'FFTW'
833 ver_info = [{'name':'sfftw',
834 'libs':['srfftw', 'sfftw'],
835 'includes':['sfftw.h', 'srfftw.h'],
836 'macros':[('SCIPY_SFFTW_H', None)]}]
837
838
839 class fftw_threads_info(fftw_info):
840 section = 'fftw'
841 dir_env_var = 'FFTW'
842 ver_info = [{'name':'fftw threads',
843 'libs':['rfftw_threads', 'fftw_threads'],
844 'includes':['fftw_threads.h', 'rfftw_threads.h'],
845 'macros':[('SCIPY_FFTW_THREADS_H', None)]}]
846
847
848 class dfftw_threads_info(fftw_info):
849 section = 'fftw'
850 dir_env_var = 'FFTW'
851 ver_info = [{'name':'dfftw threads',
852 'libs':['drfftw_threads', 'dfftw_threads'],
853 'includes':['dfftw_threads.h', 'drfftw_threads.h'],
854 'macros':[('SCIPY_DFFTW_THREADS_H', None)]}]
855
856
857 class sfftw_threads_info(fftw_info):
858 section = 'fftw'
859 dir_env_var = 'FFTW'
860 ver_info = [{'name':'sfftw threads',
861 'libs':['srfftw_threads', 'sfftw_threads'],
862 'includes':['sfftw_threads.h', 'srfftw_threads.h'],
863 'macros':[('SCIPY_SFFTW_THREADS_H', None)]}]
864
865
866 class djbfft_info(system_info):
867 section = 'djbfft'
868 dir_env_var = 'DJBFFT'
869 notfounderror = DJBFFTNotFoundError
870
871 def get_paths(self, section, key):
872 pre_dirs = system_info.get_paths(self, section, key)
873 dirs = []
874 for d in pre_dirs:
875 dirs.extend(self.combine_paths(d, ['djbfft']) + [d])
876 return [d for d in dirs if os.path.isdir(d)]
877
878 def calc_info(self):
879 lib_dirs = self.get_lib_dirs()
880 incl_dirs = self.get_include_dirs()
881 info = None
882 for d in lib_dirs:
883 p = self.combine_paths(d, ['djbfft.a'])
884 if p:
885 info = {'extra_objects': p}
886 break
887 p = self.combine_paths(d, ['libdjbfft.a', 'libdjbfft' + so_ext])
888 if p:
889 info = {'libraries': ['djbfft'], 'library_dirs': [d]}
890 break
891 if info is None:
892 return
893 for d in incl_dirs:
894 if len(self.combine_paths(d, ['fftc8.h', 'fftfreq.h'])) == 2:
895 dict_append(info, include_dirs=[d],
896 define_macros=[('SCIPY_DJBFFT_H', None)])
897 self.set_info(**info)
898 return
899 return
900
901
902 class mkl_info(system_info):
903 section = 'mkl'
904 dir_env_var = 'MKL'
905 _lib_mkl = ['mkl', 'vml', 'guide']
906
907 def get_mkl_rootdir(self):
908 mklroot = os.environ.get('MKLROOT', None)
909 if mklroot is not None:
910 return mklroot
911 paths = os.environ.get('LD_LIBRARY_PATH', '').split(os.pathsep)
912 ld_so_conf = '/etc/ld.so.conf'
913 if os.path.isfile(ld_so_conf):
914 for d in open(ld_so_conf, 'r'):
915 d = d.strip()
916 if d:
917 paths.append(d)
918 intel_mkl_dirs = []
919 for path in paths:
920 path_atoms = path.split(os.sep)
921 for m in path_atoms:
922 if m.startswith('mkl'):
923 d = os.sep.join(path_atoms[:path_atoms.index(m) + 2])
924 intel_mkl_dirs.append(d)
925 break
926 for d in paths:
927 dirs = glob(os.path.join(d, 'mkl', '*'))
928 dirs += glob(os.path.join(d, 'mkl*'))
929 for d in dirs:
930 if os.path.isdir(os.path.join(d, 'lib')):
931 return d
932 return None
933
934 def __init__(self):
935 mklroot = self.get_mkl_rootdir()
936 if mklroot is None:
937 system_info.__init__(self)
938 else:
939 from .cpuinfo import cpu
940 l = 'mkl' # use shared library
941 if cpu.is_Itanium():
942 plt = '64'
943 #l = 'mkl_ipf'
944 elif cpu.is_Xeon():
945 plt = 'em64t'
946 #l = 'mkl_em64t'
947 else:
948 plt = '32'
949 #l = 'mkl_ia32'
950 if l not in self._lib_mkl:
951 self._lib_mkl.insert(0, l)
952 system_info.__init__(
953 self,
954 default_lib_dirs=[os.path.join(mklroot, 'lib', plt)],
955 default_include_dirs=[os.path.join(mklroot, 'include')])
956
957 def calc_info(self):
958 lib_dirs = self.get_lib_dirs()
959 incl_dirs = self.get_include_dirs()
960 mkl_libs = self.get_libs('mkl_libs', self._lib_mkl)
961 info = self.check_libs2(lib_dirs, mkl_libs)
962 if info is None:
963 return
964 dict_append(info,
965 define_macros=[('SCIPY_MKL_H', None)],
966 include_dirs=incl_dirs)
967 if sys.platform == 'win32':
968 pass # win32 has no pthread library
969 else:
970 dict_append(info, libraries=['pthread'])
971 self.set_info(**info)
972
973
974 class lapack_mkl_info(mkl_info):
975
976 def calc_info(self):
977 mkl = get_info('mkl')
978 if not mkl:
979 return
980 if sys.platform == 'win32':
981 lapack_libs = self.get_libs('lapack_libs', ['mkl_lapack'])
982 else:
983 lapack_libs = self.get_libs('lapack_libs',
984 ['mkl_lapack32', 'mkl_lapack64'])
985
986 info = {'libraries': lapack_libs}
987 dict_append(info, **mkl)
988 self.set_info(**info)
989
990
991 class blas_mkl_info(mkl_info):
992 pass
993
994
995 class atlas_info(system_info):
996 section = 'atlas'
997 dir_env_var = 'ATLAS'
998 _lib_names = ['f77blas', 'cblas']
999 if sys.platform[:7] == 'freebsd':
1000 _lib_atlas = ['atlas_r']
1001 _lib_lapack = ['alapack_r']
1002 else:
1003 _lib_atlas = ['atlas']
1004 _lib_lapack = ['lapack']
1005
1006 notfounderror = AtlasNotFoundError
1007
1008 def get_paths(self, section, key):
1009 pre_dirs = system_info.get_paths(self, section, key)
1010 dirs = []
1011 for d in pre_dirs:
1012 dirs.extend(self.combine_paths(d, ['atlas*', 'ATLAS*',
1013 'sse', '3dnow', 'sse2']) + [d])
1014 return [d for d in dirs if os.path.isdir(d)]
1015
1016 def calc_info(self):
1017 lib_dirs = self.get_lib_dirs()
1018 info = {}
1019 atlas_libs = self.get_libs('atlas_libs',
1020 self._lib_names + self._lib_atlas)
1021 lapack_libs = self.get_libs('lapack_libs', self._lib_lapack)
1022 atlas = None
1023 lapack = None
1024 atlas_1 = None
1025 for d in lib_dirs:
1026 atlas = self.check_libs2(d, atlas_libs, [])
1027 lapack_atlas = self.check_libs2(d, ['lapack_atlas'], [])
1028 if atlas is not None:
1029 lib_dirs2 = [d] + self.combine_paths(d, ['atlas*', 'ATLAS*'])
1030 lapack = self.check_libs2(lib_dirs2, lapack_libs, [])
1031 if lapack is not None:
1032 break
1033 if atlas:
1034 atlas_1 = atlas
1035 log.info(self.__class__)
1036 if atlas is None:
1037 atlas = atlas_1
1038 if atlas is None:
1039 return
1040 include_dirs = self.get_include_dirs()
1041 h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None])
1042 h = h[0]
1043 if h:
1044 h = os.path.dirname(h)
1045 dict_append(info, include_dirs=[h])
1046 info['language'] = 'c'
1047 if lapack is not None:
1048 dict_append(info, **lapack)
1049 dict_append(info, **atlas)
1050 elif 'lapack_atlas' in atlas['libraries']:
1051 dict_append(info, **atlas)
1052 dict_append(info,
1053 define_macros=[('ATLAS_WITH_LAPACK_ATLAS', None)])
1054 self.set_info(**info)
1055 return
1056 else:
1057 dict_append(info, **atlas)
1058 dict_append(info, define_macros=[('ATLAS_WITHOUT_LAPACK', None)])
1059 message = """
1060 *********************************************************************
1061 Could not find lapack library within the ATLAS installation.
1062 *********************************************************************
1063 """
1064 warnings.warn(message)
1065 self.set_info(**info)
1066 return
1067
1068 # Check if lapack library is complete, only warn if it is not.
1069 lapack_dir = lapack['library_dirs'][0]
1070 lapack_name = lapack['libraries'][0]
1071 lapack_lib = None
1072 lib_prefixes = ['lib']
1073 if sys.platform == 'win32':
1074 lib_prefixes.append('')
1075 for e in self.library_extensions():
1076 for prefix in lib_prefixes:
1077 fn = os.path.join(lapack_dir, prefix + lapack_name + e)
1078 if os.path.exists(fn):
1079 lapack_lib = fn
1080 break
1081 if lapack_lib:
1082 break
1083 if lapack_lib is not None:
1084 sz = os.stat(lapack_lib)[6]
1085 if sz <= 4000 * 1024:
1086 message = """
1087 *********************************************************************
1088 Lapack library (from ATLAS) is probably incomplete:
1089 size of %s is %sk (expected >4000k)
1090
1091 Follow the instructions in the KNOWN PROBLEMS section of the file
1092 numpy/INSTALL.txt.
1093 *********************************************************************
1094 """ % (lapack_lib, sz / 1024)
1095 warnings.warn(message)
1096 else:
1097 info['language'] = 'f77'
1098
1099 atlas_version, atlas_extra_info = get_atlas_version(**atlas)
1100 dict_append(info, **atlas_extra_info)
1101
1102 self.set_info(**info)
1103
1104
1105 class atlas_blas_info(atlas_info):
1106 _lib_names = ['f77blas', 'cblas']
1107
1108 def calc_info(self):
1109 lib_dirs = self.get_lib_dirs()
1110 info = {}
1111 atlas_libs = self.get_libs('atlas_libs',
1112 self._lib_names + self._lib_atlas)
1113 atlas = self.check_libs2(lib_dirs, atlas_libs, [])
1114 if atlas is None:
1115 return
1116 include_dirs = self.get_include_dirs()
1117 h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None])
1118 h = h[0]
1119 if h:
1120 h = os.path.dirname(h)
1121 dict_append(info, include_dirs=[h])
1122 info['language'] = 'c'
1123
1124 atlas_version, atlas_extra_info = get_atlas_version(**atlas)
1125 dict_append(atlas, **atlas_extra_info)
1126
1127 dict_append(info, **atlas)
1128
1129 self.set_info(**info)
1130 return
1131
1132
1133 class atlas_threads_info(atlas_info):
1134 dir_env_var = ['PTATLAS', 'ATLAS']
1135 _lib_names = ['ptf77blas', 'ptcblas']
1136
1137
1138 class atlas_blas_threads_info(atlas_blas_info):
1139 dir_env_var = ['PTATLAS', 'ATLAS']
1140 _lib_names = ['ptf77blas', 'ptcblas']
1141
1142
1143 class lapack_atlas_info(atlas_info):
1144 _lib_names = ['lapack_atlas'] + atlas_info._lib_names
1145
1146
1147 class lapack_atlas_threads_info(atlas_threads_info):
1148 _lib_names = ['lapack_atlas'] + atlas_threads_info._lib_names
1149
1150
1151 class lapack_info(system_info):
1152 section = 'lapack'
1153 dir_env_var = 'LAPACK'
1154 _lib_names = ['lapack']
1155 notfounderror = LapackNotFoundError
1156
1157 def calc_info(self):
1158 lib_dirs = self.get_lib_dirs()
1159
1160 lapack_libs = self.get_libs('lapack_libs', self._lib_names)
1161 info = self.check_libs(lib_dirs, lapack_libs, [])
1162 if info is None:
1163 return
1164 info['language'] = 'f77'
1165 self.set_info(**info)
1166
1167
1168 class lapack_src_info(system_info):
1169 section = 'lapack_src'
1170 dir_env_var = 'LAPACK_SRC'
1171 notfounderror = LapackSrcNotFoundError
1172
1173 def get_paths(self, section, key):
1174 pre_dirs = system_info.get_paths(self, section, key)
1175 dirs = []
1176 for d in pre_dirs:
1177 dirs.extend([d] + self.combine_paths(d, ['LAPACK*/SRC', 'SRC']))
1178 return [d for d in dirs if os.path.isdir(d)]
1179
1180 def calc_info(self):
1181 src_dirs = self.get_src_dirs()
1182 src_dir = ''
1183 for d in src_dirs:
1184 if os.path.isfile(os.path.join(d, 'dgesv.f')):
1185 src_dir = d
1186 break
1187 if not src_dir:
1188 #XXX: Get sources from netlib. May be ask first.
1189 return
1190 # The following is extracted from LAPACK-3.0/SRC/Makefile.
1191 # Added missing names from lapack-lite-3.1.1/SRC/Makefile
1192 # while keeping removed names for Lapack-3.0 compatibility.
1193 allaux = '''
1194 ilaenv ieeeck lsame lsamen xerbla
1195 iparmq
1196 ''' # *.f
1197 laux = '''
1198 bdsdc bdsqr disna labad lacpy ladiv lae2 laebz laed0 laed1
1199 laed2 laed3 laed4 laed5 laed6 laed7 laed8 laed9 laeda laev2
1200 lagtf lagts lamch lamrg lanst lapy2 lapy3 larnv larrb larre
1201 larrf lartg laruv las2 lascl lasd0 lasd1 lasd2 lasd3 lasd4
1202 lasd5 lasd6 lasd7 lasd8 lasd9 lasda lasdq lasdt laset lasq1
1203 lasq2 lasq3 lasq4 lasq5 lasq6 lasr lasrt lassq lasv2 pttrf
1204 stebz stedc steqr sterf
1205
1206 larra larrc larrd larr larrk larrj larrr laneg laisnan isnan
1207 lazq3 lazq4
1208 ''' # [s|d]*.f
1209 lasrc = '''
1210 gbbrd gbcon gbequ gbrfs gbsv gbsvx gbtf2 gbtrf gbtrs gebak
1211 gebal gebd2 gebrd gecon geequ gees geesx geev geevx gegs gegv
1212 gehd2 gehrd gelq2 gelqf gels gelsd gelss gelsx gelsy geql2
1213 geqlf geqp3 geqpf geqr2 geqrf gerfs gerq2 gerqf gesc2 gesdd
1214 gesv gesvd gesvx getc2 getf2 getrf getri getrs ggbak ggbal
1215 gges ggesx ggev ggevx ggglm gghrd gglse ggqrf ggrqf ggsvd
1216 ggsvp gtcon gtrfs gtsv gtsvx gttrf gttrs gtts2 hgeqz hsein
1217 hseqr labrd lacon laein lags2 lagtm lahqr lahrd laic1 lals0
1218 lalsa lalsd langb lange langt lanhs lansb lansp lansy lantb
1219 lantp lantr lapll lapmt laqgb laqge laqp2 laqps laqsb laqsp
1220 laqsy lar1v lar2v larf larfb larfg larft larfx largv larrv
1221 lartv larz larzb larzt laswp lasyf latbs latdf latps latrd
1222 latrs latrz latzm lauu2 lauum pbcon pbequ pbrfs pbstf pbsv
1223 pbsvx pbtf2 pbtrf pbtrs pocon poequ porfs posv posvx potf2
1224 potrf potri potrs ppcon ppequ pprfs ppsv ppsvx pptrf pptri
1225 pptrs ptcon pteqr ptrfs ptsv ptsvx pttrs ptts2 spcon sprfs
1226 spsv spsvx sptrf sptri sptrs stegr stein sycon syrfs sysv
1227 sysvx sytf2 sytrf sytri sytrs tbcon tbrfs tbtrs tgevc tgex2
1228 tgexc tgsen tgsja tgsna tgsy2 tgsyl tpcon tprfs tptri tptrs
1229 trcon trevc trexc trrfs trsen trsna trsyl trti2 trtri trtrs
1230 tzrqf tzrzf
1231
1232 lacn2 lahr2 stemr laqr0 laqr1 laqr2 laqr3 laqr4 laqr5
1233 ''' # [s|c|d|z]*.f
1234 sd_lasrc = '''
1235 laexc lag2 lagv2 laln2 lanv2 laqtr lasy2 opgtr opmtr org2l
1236 org2r orgbr orghr orgl2 orglq orgql orgqr orgr2 orgrq orgtr
1237 orm2l orm2r ormbr ormhr orml2 ormlq ormql ormqr ormr2 ormr3
1238 ormrq ormrz ormtr rscl sbev sbevd sbevx sbgst sbgv sbgvd sbgvx
1239 sbtrd spev spevd spevx spgst spgv spgvd spgvx sptrd stev stevd
1240 stevr stevx syev syevd syevr syevx sygs2 sygst sygv sygvd
1241 sygvx sytd2 sytrd
1242 ''' # [s|d]*.f
1243 cz_lasrc = '''
1244 bdsqr hbev hbevd hbevx hbgst hbgv hbgvd hbgvx hbtrd hecon heev
1245 heevd heevr heevx hegs2 hegst hegv hegvd hegvx herfs hesv
1246 hesvx hetd2 hetf2 hetrd hetrf hetri hetrs hpcon hpev hpevd
1247 hpevx hpgst hpgv hpgvd hpgvx hprfs hpsv hpsvx hptrd hptrf
1248 hptri hptrs lacgv lacp2 lacpy lacrm lacrt ladiv laed0 laed7
1249 laed8 laesy laev2 lahef lanhb lanhe lanhp lanht laqhb laqhe
1250 laqhp larcm larnv lartg lascl laset lasr lassq pttrf rot spmv
1251 spr stedc steqr symv syr ung2l ung2r ungbr unghr ungl2 unglq
1252 ungql ungqr ungr2 ungrq ungtr unm2l unm2r unmbr unmhr unml2
1253 unmlq unmql unmqr unmr2 unmr3 unmrq unmrz unmtr upgtr upmtr
1254 ''' # [c|z]*.f
1255 #######
1256 sclaux = laux + ' econd ' # s*.f
1257 dzlaux = laux + ' secnd ' # d*.f
1258 slasrc = lasrc + sd_lasrc # s*.f
1259 dlasrc = lasrc + sd_lasrc # d*.f
1260 clasrc = lasrc + cz_lasrc + ' srot srscl ' # c*.f
1261 zlasrc = lasrc + cz_lasrc + ' drot drscl ' # z*.f
1262 oclasrc = ' icmax1 scsum1 ' # *.f
1263 ozlasrc = ' izmax1 dzsum1 ' # *.f
1264 sources = ['s%s.f' % f for f in (sclaux + slasrc).split()] \
1265 + ['d%s.f' % f for f in (dzlaux + dlasrc).split()] \
1266 + ['c%s.f' % f for f in (clasrc).split()] \
1267 + ['z%s.f' % f for f in (zlasrc).split()] \
1268 + ['%s.f' % f for f in (allaux + oclasrc + ozlasrc).split()]
1269 sources = [os.path.join(src_dir, f) for f in sources]
1270 # Lapack 3.1:
1271 src_dir2 = os.path.join(src_dir, '..', 'INSTALL')
1272 sources += [os.path.join(src_dir2, p + 'lamch.f') for p in 'sdcz']
1273 # Lapack 3.2.1:
1274 sources += [os.path.join(src_dir, p + 'larfp.f') for p in 'sdcz']
1275 sources += [os.path.join(src_dir, 'ila' + p + 'lr.f') for p in 'sdcz']
1276 sources += [os.path.join(src_dir, 'ila' + p + 'lc.f') for p in 'sdcz']
1277 # Should we check here actual existence of source files?
1278 # Yes, the file listing is different between 3.0 and 3.1
1279 # versions.
1280 sources = [f for f in sources if os.path.isfile(f)]
1281 info = {'sources': sources, 'language': 'f77'}
1282 self.set_info(**info)
1283
1284 atlas_version_c_text = r'''
1285 /* This file is generated from numpy/distutils/system_info.py */
1286 void ATL_buildinfo(void);
1287 int main(void) {
1288 ATL_buildinfo();
1289 return 0;
1290 }
1291 '''
1292
1293 _cached_atlas_version = {}
1294
1295
1296 def get_atlas_version(**config):
1297 libraries = config.get('libraries', [])
1298 library_dirs = config.get('library_dirs', [])
1299 key = (tuple(libraries), tuple(library_dirs))
1300 if key in _cached_atlas_version:
1301 return _cached_atlas_version[key]
1302 c = cmd_config(Distribution())
1303 atlas_version = None
1304 info = {}
1305 try:
1306 s, o = c.get_output(atlas_version_c_text,
1307 libraries=libraries, library_dirs=library_dirs,
1308 use_tee=(system_info.verbosity > 0))
1309 if s and re.search(r'undefined reference to `_gfortran', o, re.M):
1310 s, o = c.get_output(atlas_version_c_text,
1311 libraries=libraries + ['gfortran'],
1312 library_dirs=library_dirs,
1313 use_tee=(system_info.verbosity > 0))
1314 if not s:
1315 warnings.warn("""
1316 *****************************************************
1317 Linkage with ATLAS requires gfortran. Use
1318
1319 python setup.py config_fc --fcompiler=gnu95 ...
1320
1321 when building extension libraries that use ATLAS.
1322 Make sure that -lgfortran is used for C++ extensions.
1323 *****************************************************
1324 """)
1325 dict_append(info, language='f90',
1326 define_macros=[('ATLAS_REQUIRES_GFORTRAN', None)])
1327 except Exception: # failed to get version from file -- maybe on Windows
1328 # look at directory name
1329 for o in library_dirs:
1330 m = re.search(r'ATLAS_(?P<version>\d+[.]\d+[.]\d+)_', o)
1331 if m:
1332 atlas_version = m.group('version')
1333 if atlas_version is not None:
1334 break
1335
1336 # final choice --- look at ATLAS_VERSION environment
1337 # variable
1338 if atlas_version is None:
1339 atlas_version = os.environ.get('ATLAS_VERSION', None)
1340 if atlas_version:
1341 dict_append(info, define_macros=[(
1342 'ATLAS_INFO', '"\\"%s\\""' % atlas_version)
1343 ])
1344 else:
1345 dict_append(info, define_macros=[('NO_ATLAS_INFO', -1)])
1346 return atlas_version or '?.?.?', info
1347
1348 if not s:
1349 m = re.search(r'ATLAS version (?P<version>\d+[.]\d+[.]\d+)', o)
1350 if m:
1351 atlas_version = m.group('version')
1352 if atlas_version is None:
1353 if re.search(r'undefined symbol: ATL_buildinfo', o, re.M):
1354 atlas_version = '3.2.1_pre3.3.6'
1355 else:
1356 log.info('Status: %d', s)
1357 log.info('Output: %s', o)
1358
1359 if atlas_version == '3.2.1_pre3.3.6':
1360 dict_append(info, define_macros=[('NO_ATLAS_INFO', -2)])
1361 else:
1362 dict_append(info, define_macros=[(
1363 'ATLAS_INFO', '"\\"%s\\""' % atlas_version)
1364 ])
1365 result = _cached_atlas_version[key] = atlas_version, info
1366 return result
1367
1368
1369
1370 class lapack_opt_info(system_info):
1371
1372 notfounderror = LapackNotFoundError
1373
1374 def calc_info(self):
1375
1376 openblas_info = get_info('openblas_lapack')
1377 if openblas_info:
1378 self.set_info(**openblas_info)
1379 return
1380
1381 lapack_mkl_info = get_info('lapack_mkl')
1382 if lapack_mkl_info:
1383 self.set_info(**lapack_mkl_info)
1384 return
1385
1386 atlas_info = get_info('atlas_threads')
1387 if not atlas_info:
1388 atlas_info = get_info('atlas')
1389
1390 if sys.platform == 'darwin' and not atlas_info:
1391 # Use the system lapack from Accelerate or vecLib under OSX
1392 args = []
1393 link_args = []
1394 if get_platform()[-4:] == 'i386' or 'intel' in get_platform() or \
1395 'x86_64' in get_platform() or \
1396 'i386' in platform.platform():
1397 intel = 1
1398 else:
1399 intel = 0
1400 if os.path.exists('/System/Library/Frameworks'
1401 '/Accelerate.framework/'):
1402 if intel:
1403 args.extend(['-msse3', '-DAPPLE_ACCELERATE_SGEMV_PATCH'])
1404 else:
1405 args.extend(['-faltivec'])
1406 link_args.extend(['-Wl,-framework', '-Wl,Accelerate'])
1407 elif os.path.exists('/System/Library/Frameworks'
1408 '/vecLib.framework/'):
1409 if intel:
1410 args.extend(['-msse3'])
1411 else:
1412 args.extend(['-faltivec'])
1413 link_args.extend(['-Wl,-framework', '-Wl,vecLib'])
1414 if args:
1415 self.set_info(extra_compile_args=args,
1416 extra_link_args=link_args,
1417 define_macros=[('NO_ATLAS_INFO', 3)])
1418 return
1419
1420 #atlas_info = {} ## uncomment for testing
1421 need_lapack = 0
1422 need_blas = 0
1423 info = {}
1424 if atlas_info:
1425 l = atlas_info.get('define_macros', [])
1426 if ('ATLAS_WITH_LAPACK_ATLAS', None) in l \
1427 or ('ATLAS_WITHOUT_LAPACK', None) in l:
1428 need_lapack = 1
1429 info = atlas_info
1430
1431 else:
1432 warnings.warn(AtlasNotFoundError.__doc__)
1433 need_blas = 1
1434 need_lapack = 1
1435 dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)])
1436
1437 if need_lapack:
1438 lapack_info = get_info('lapack')
1439 #lapack_info = {} ## uncomment for testing
1440 if lapack_info:
1441 dict_append(info, **lapack_info)
1442 else:
1443 warnings.warn(LapackNotFoundError.__doc__)
1444 lapack_src_info = get_info('lapack_src')
1445 if not lapack_src_info:
1446 warnings.warn(LapackSrcNotFoundError.__doc__)
1447 return
1448 dict_append(info, libraries=[('flapack_src', lapack_src_info)])
1449
1450 if need_blas:
1451 blas_info = get_info('blas')
1452 #blas_info = {} ## uncomment for testing
1453 if blas_info:
1454 dict_append(info, **blas_info)
1455 else:
1456 warnings.warn(BlasNotFoundError.__doc__)
1457 blas_src_info = get_info('blas_src')
1458 if not blas_src_info:
1459 warnings.warn(BlasSrcNotFoundError.__doc__)
1460 return
1461 dict_append(info, libraries=[('fblas_src', blas_src_info)])
1462
1463 self.set_info(**info)
1464 return
1465
1466
1467 class blas_opt_info(system_info):
1468
1469 notfounderror = BlasNotFoundError
1470
1471 def calc_info(self):
1472
1473 blas_mkl_info = get_info('blas_mkl')
1474 if blas_mkl_info:
1475 self.set_info(**blas_mkl_info)
1476 return
1477
1478 openblas_info = get_info('openblas')
1479 if openblas_info:
1480 self.set_info(**openblas_info)
1481 return
1482
1483 atlas_info = get_info('atlas_blas_threads')
1484 if not atlas_info:
1485 atlas_info = get_info('atlas_blas')
1486
1487 if sys.platform == 'darwin' and not atlas_info:
1488 # Use the system BLAS from Accelerate or vecLib under OSX
1489 args = []
1490 link_args = []
1491 if get_platform()[-4:] == 'i386' or 'intel' in get_platform() or \
1492 'x86_64' in get_platform() or \
1493 'i386' in platform.platform():
1494 intel = 1
1495 else:
1496 intel = 0
1497 if os.path.exists('/System/Library/Frameworks'
1498 '/Accelerate.framework/'):
1499 if intel:
1500 args.extend(['-msse3', '-DAPPLE_ACCELERATE_SGEMV_PATCH'])
1501 else:
1502 args.extend(['-faltivec'])
1503 args.extend([
1504 '-I/System/Library/Frameworks/vecLib.framework/Headers'])
1505 link_args.extend(['-Wl,-framework', '-Wl,Accelerate'])
1506 elif os.path.exists('/System/Library/Frameworks'
1507 '/vecLib.framework/'):
1508 if intel:
1509 args.extend(['-msse3'])
1510 else:
1511 args.extend(['-faltivec'])
1512 args.extend([
1513 '-I/System/Library/Frameworks/vecLib.framework/Headers'])
1514 link_args.extend(['-Wl,-framework', '-Wl,vecLib'])
1515 if args:
1516 self.set_info(extra_compile_args=args,
1517 extra_link_args=link_args,
1518 define_macros=[('NO_ATLAS_INFO', 3)])
1519 return
1520
1521 need_blas = 0
1522 info = {}
1523 if atlas_info:
1524 info = atlas_info
1525 else:
1526 warnings.warn(AtlasNotFoundError.__doc__)
1527 need_blas = 1
1528 dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)])
1529
1530 if need_blas:
1531 blas_info = get_info('blas')
1532 if blas_info:
1533 dict_append(info, **blas_info)
1534 else:
1535 warnings.warn(BlasNotFoundError.__doc__)
1536 blas_src_info = get_info('blas_src')
1537 if not blas_src_info:
1538 warnings.warn(BlasSrcNotFoundError.__doc__)
1539 return
1540 dict_append(info, libraries=[('fblas_src', blas_src_info)])
1541
1542 self.set_info(**info)
1543 return
1544
1545
1546 class blas_info(system_info):
1547 section = 'blas'
1548 dir_env_var = 'BLAS'
1549 _lib_names = ['blas']
1550 notfounderror = BlasNotFoundError
1551
1552 def calc_info(self):
1553 lib_dirs = self.get_lib_dirs()
1554
1555 blas_libs = self.get_libs('blas_libs', self._lib_names)
1556 info = self.check_libs(lib_dirs, blas_libs, [])
1557 if info is None:
1558 return
1559 info['language'] = 'f77' # XXX: is it generally true?
1560 self.set_info(**info)
1561
1562
1563 class openblas_info(blas_info):
1564 section = 'openblas'
1565 dir_env_var = 'OPENBLAS'
1566 _lib_names = ['openblas']
1567 notfounderror = BlasNotFoundError
1568
1569 def check_embedded_lapack(self, info):
1570 return True
1571
1572 def calc_info(self):
1573 lib_dirs = self.get_lib_dirs()
1574
1575 openblas_libs = self.get_libs('libraries', self._lib_names)
1576 if openblas_libs == self._lib_names: # backward compat with 1.8.0
1577 openblas_libs = self.get_libs('openblas_libs', self._lib_names)
1578 info = self.check_libs(lib_dirs, openblas_libs, [])
1579 if info is None:
1580 return
1581
1582 if not self.check_embedded_lapack(info):
1583 return None
1584
1585 info['language'] = 'f77' # XXX: is it generally true?
1586 self.set_info(**info)
1587
1588
1589 class openblas_lapack_info(openblas_info):
1590 section = 'openblas'
1591 dir_env_var = 'OPENBLAS'
1592 _lib_names = ['openblas']
1593 notfounderror = BlasNotFoundError
1594
1595 def check_embedded_lapack(self, info):
1596 res = False
1597 c = distutils.ccompiler.new_compiler()
1598 tmpdir = tempfile.mkdtemp()
1599 s = """void zungqr();
1600 int main(int argc, const char *argv[])
1601 {
1602 zungqr_();
1603 return 0;
1604 }"""
1605 src = os.path.join(tmpdir, 'source.c')
1606 out = os.path.join(tmpdir, 'a.out')
1607 try:
1608 with open(src, 'wt') as f:
1609 f.write(s)
1610 obj = c.compile([src], output_dir=tmpdir)
1611 try:
1612 c.link_executable(obj, out, libraries=info['libraries'],
1613 library_dirs=info['library_dirs'])
1614 res = True
1615 except distutils.ccompiler.LinkError:
1616 res = False
1617 finally:
1618 shutil.rmtree(tmpdir)
1619 return res
1620
1621
1622 class blas_src_info(system_info):
1623 section = 'blas_src'
1624 dir_env_var = 'BLAS_SRC'
1625 notfounderror = BlasSrcNotFoundError
1626
1627 def get_paths(self, section, key):
1628 pre_dirs = system_info.get_paths(self, section, key)
1629 dirs = []
1630 for d in pre_dirs:
1631 dirs.extend([d] + self.combine_paths(d, ['blas']))
1632 return [d for d in dirs if os.path.isdir(d)]
1633
1634 def calc_info(self):
1635 src_dirs = self.get_src_dirs()
1636 src_dir = ''
1637 for d in src_dirs:
1638 if os.path.isfile(os.path.join(d, 'daxpy.f')):
1639 src_dir = d
1640 break
1641 if not src_dir:
1642 #XXX: Get sources from netlib. May be ask first.
1643 return
1644 blas1 = '''
1645 caxpy csscal dnrm2 dzasum saxpy srotg zdotc ccopy cswap drot
1646 dznrm2 scasum srotm zdotu cdotc dasum drotg icamax scnrm2
1647 srotmg zdrot cdotu daxpy drotm idamax scopy sscal zdscal crotg
1648 dcabs1 drotmg isamax sdot sswap zrotg cscal dcopy dscal izamax
1649 snrm2 zaxpy zscal csrot ddot dswap sasum srot zcopy zswap
1650 scabs1
1651 '''
1652 blas2 = '''
1653 cgbmv chpmv ctrsv dsymv dtrsv sspr2 strmv zhemv ztpmv cgemv
1654 chpr dgbmv dsyr lsame ssymv strsv zher ztpsv cgerc chpr2 dgemv
1655 dsyr2 sgbmv ssyr xerbla zher2 ztrmv cgeru ctbmv dger dtbmv
1656 sgemv ssyr2 zgbmv zhpmv ztrsv chbmv ctbsv dsbmv dtbsv sger
1657 stbmv zgemv zhpr chemv ctpmv dspmv dtpmv ssbmv stbsv zgerc
1658 zhpr2 cher ctpsv dspr dtpsv sspmv stpmv zgeru ztbmv cher2
1659 ctrmv dspr2 dtrmv sspr stpsv zhbmv ztbsv
1660 '''
1661 blas3 = '''
1662 cgemm csymm ctrsm dsyrk sgemm strmm zhemm zsyr2k chemm csyr2k
1663 dgemm dtrmm ssymm strsm zher2k zsyrk cher2k csyrk dsymm dtrsm
1664 ssyr2k zherk ztrmm cherk ctrmm dsyr2k ssyrk zgemm zsymm ztrsm
1665 '''
1666 sources = [os.path.join(src_dir, f + '.f') \
1667 for f in (blas1 + blas2 + blas3).split()]
1668 #XXX: should we check here actual existence of source files?
1669 sources = [f for f in sources if os.path.isfile(f)]
1670 info = {'sources': sources, 'language': 'f77'}
1671 self.set_info(**info)
1672
1673
1674 class x11_info(system_info):
1675 section = 'x11'
1676 notfounderror = X11NotFoundError
1677
1678 def __init__(self):
1679 system_info.__init__(self,
1680 default_lib_dirs=default_x11_lib_dirs,
1681 default_include_dirs=default_x11_include_dirs)
1682
1683 def calc_info(self):
1684 if sys.platform in ['win32']:
1685 return
1686 lib_dirs = self.get_lib_dirs()
1687 include_dirs = self.get_include_dirs()
1688 x11_libs = self.get_libs('x11_libs', ['X11'])
1689 info = self.check_libs(lib_dirs, x11_libs, [])
1690 if info is None:
1691 return
1692 inc_dir = None
1693 for d in include_dirs:
1694 if self.combine_paths(d, 'X11/X.h'):
1695 inc_dir = d
1696 break
1697 if inc_dir is not None:
1698 dict_append(info, include_dirs=[inc_dir])
1699 self.set_info(**info)
1700
1701
1702 class _numpy_info(system_info):
1703 section = 'Numeric'
1704 modulename = 'Numeric'
1705 notfounderror = NumericNotFoundError
1706
1707 def __init__(self):
1708 include_dirs = []
1709 try:
1710 module = __import__(self.modulename)
1711 prefix = []
1712 for name in module.__file__.split(os.sep):
1713 if name == 'lib':
1714 break
1715 prefix.append(name)
1716
1717 # Ask numpy for its own include path before attempting
1718 # anything else
1719 try:
1720 include_dirs.append(getattr(module, 'get_include')())
1721 except AttributeError:
1722 pass
1723
1724 include_dirs.append(distutils.sysconfig.get_python_inc(
1725 prefix=os.sep.join(prefix)))
1726 except ImportError:
1727 pass
1728 py_incl_dir = distutils.sysconfig.get_python_inc()
1729 include_dirs.append(py_incl_dir)
1730 py_pincl_dir = distutils.sysconfig.get_python_inc(plat_specific=True)
1731 if py_pincl_dir not in include_dirs:
1732 include_dirs.append(py_pincl_dir)
1733 for d in default_include_dirs:
1734 d = os.path.join(d, os.path.basename(py_incl_dir))
1735 if d not in include_dirs:
1736 include_dirs.append(d)
1737 system_info.__init__(self,
1738 default_lib_dirs=[],
1739 default_include_dirs=include_dirs)
1740
1741 def calc_info(self):
1742 try:
1743 module = __import__(self.modulename)
1744 except ImportError:
1745 return
1746 info = {}
1747 macros = []
1748 for v in ['__version__', 'version']:
1749 vrs = getattr(module, v, None)
1750 if vrs is None:
1751 continue
1752 macros = [(self.modulename.upper() + '_VERSION',
1753 '"\\"%s\\""' % (vrs)),
1754 (self.modulename.upper(), None)]
1755 break
1756 ## try:
1757 ## macros.append(
1758 ## (self.modulename.upper()+'_VERSION_HEX',
1759 ## hex(vstr2hex(module.__version__))),
1760 ## )
1761 ## except Exception as msg:
1762 ## print msg
1763 dict_append(info, define_macros=macros)
1764 include_dirs = self.get_include_dirs()
1765 inc_dir = None
1766 for d in include_dirs:
1767 if self.combine_paths(d,
1768 os.path.join(self.modulename,
1769 'arrayobject.h')):
1770 inc_dir = d
1771 break
1772 if inc_dir is not None:
1773 dict_append(info, include_dirs=[inc_dir])
1774 if info:
1775 self.set_info(**info)
1776 return
1777
1778
1779 class numarray_info(_numpy_info):
1780 section = 'numarray'
1781 modulename = 'numarray'
1782
1783
1784 class Numeric_info(_numpy_info):
1785 section = 'Numeric'
1786 modulename = 'Numeric'
1787
1788
1789 class numpy_info(_numpy_info):
1790 section = 'numpy'
1791 modulename = 'numpy'
1792
1793
1794 class numerix_info(system_info):
1795 section = 'numerix'
1796
1797 def calc_info(self):
1798 which = None, None
1799 if os.getenv("NUMERIX"):
1800 which = os.getenv("NUMERIX"), "environment var"
1801 # If all the above fail, default to numpy.
1802 if which[0] is None:
1803 which = "numpy", "defaulted"
1804 try:
1805 import numpy
1806 which = "numpy", "defaulted"
1807 except ImportError:
1808 msg1 = str(get_exception())
1809 try:
1810 import Numeric
1811 which = "numeric", "defaulted"
1812 except ImportError:
1813 msg2 = str(get_exception())
1814 try:
1815 import numarray
1816 which = "numarray", "defaulted"
1817 except ImportError:
1818 msg3 = str(get_exception())
1819 log.info(msg1)
1820 log.info(msg2)
1821 log.info(msg3)
1822 which = which[0].strip().lower(), which[1]
1823 if which[0] not in ["numeric", "numarray", "numpy"]:
1824 raise ValueError("numerix selector must be either 'Numeric' "
1825 "or 'numarray' or 'numpy' but the value obtained"
1826 " from the %s was '%s'." % (which[1], which[0]))
1827 os.environ['NUMERIX'] = which[0]
1828 self.set_info(**get_info(which[0]))
1829
1830
1831 class f2py_info(system_info):
1832 def calc_info(self):
1833 try:
1834 import numpy.f2py as f2py
1835 except ImportError:
1836 return
1837 f2py_dir = os.path.join(os.path.dirname(f2py.__file__), 'src')
1838 self.set_info(sources=[os.path.join(f2py_dir, 'fortranobject.c')],
1839 include_dirs=[f2py_dir])
1840 return
1841
1842
1843 class boost_python_info(system_info):
1844 section = 'boost_python'
1845 dir_env_var = 'BOOST'
1846
1847 def get_paths(self, section, key):
1848 pre_dirs = system_info.get_paths(self, section, key)
1849 dirs = []
1850 for d in pre_dirs:
1851 dirs.extend([d] + self.combine_paths(d, ['boost*']))
1852 return [d for d in dirs if os.path.isdir(d)]
1853
1854 def calc_info(self):
1855 src_dirs = self.get_src_dirs()
1856 src_dir = ''
1857 for d in src_dirs:
1858 if os.path.isfile(os.path.join(d, 'libs', 'python', 'src',
1859 'module.cpp')):
1860 src_dir = d
1861 break
1862 if not src_dir:
1863 return
1864 py_incl_dirs = [distutils.sysconfig.get_python_inc()]
1865 py_pincl_dir = distutils.sysconfig.get_python_inc(plat_specific=True)
1866 if py_pincl_dir not in py_incl_dirs:
1867 py_incl_dirs.append(py_pincl_dir)
1868 srcs_dir = os.path.join(src_dir, 'libs', 'python', 'src')
1869 bpl_srcs = glob(os.path.join(srcs_dir, '*.cpp'))
1870 bpl_srcs += glob(os.path.join(srcs_dir, '*', '*.cpp'))
1871 info = {'libraries': [('boost_python_src',
1872 {'include_dirs': [src_dir] + py_incl_dirs,
1873 'sources':bpl_srcs}
1874 )],
1875 'include_dirs': [src_dir],
1876 }
1877 if info:
1878 self.set_info(**info)
1879 return
1880
1881
1882 class agg2_info(system_info):
1883 section = 'agg2'
1884 dir_env_var = 'AGG2'
1885
1886 def get_paths(self, section, key):
1887 pre_dirs = system_info.get_paths(self, section, key)
1888 dirs = []
1889 for d in pre_dirs:
1890 dirs.extend([d] + self.combine_paths(d, ['agg2*']))
1891 return [d for d in dirs if os.path.isdir(d)]
1892
1893 def calc_info(self):
1894 src_dirs = self.get_src_dirs()
1895 src_dir = ''
1896 for d in src_dirs:
1897 if os.path.isfile(os.path.join(d, 'src', 'agg_affine_matrix.cpp')):
1898 src_dir = d
1899 break
1900 if not src_dir:
1901 return
1902 if sys.platform == 'win32':
1903 agg2_srcs = glob(os.path.join(src_dir, 'src', 'platform',
1904 'win32', 'agg_win32_bmp.cpp'))
1905 else:
1906 agg2_srcs = glob(os.path.join(src_dir, 'src', '*.cpp'))
1907 agg2_srcs += [os.path.join(src_dir, 'src', 'platform',
1908 'X11',
1909 'agg_platform_support.cpp')]
1910
1911 info = {'libraries':
1912 [('agg2_src',
1913 {'sources': agg2_srcs,
1914 'include_dirs': [os.path.join(src_dir, 'include')],
1915 }
1916 )],
1917 'include_dirs': [os.path.join(src_dir, 'include')],
1918 }
1919 if info:
1920 self.set_info(**info)
1921 return
1922
1923
1924 class _pkg_config_info(system_info):
1925 section = None
1926 config_env_var = 'PKG_CONFIG'
1927 default_config_exe = 'pkg-config'
1928 append_config_exe = ''
1929 version_macro_name = None
1930 release_macro_name = None
1931 version_flag = '--modversion'
1932 cflags_flag = '--cflags'
1933
1934 def get_config_exe(self):
1935 if self.config_env_var in os.environ:
1936 return os.environ[self.config_env_var]
1937 return self.default_config_exe
1938
1939 def get_config_output(self, config_exe, option):
1940 cmd = config_exe + ' ' + self.append_config_exe + ' ' + option
1941 s, o = exec_command(cmd, use_tee=0)
1942 if not s:
1943 return o
1944
1945 def calc_info(self):
1946 config_exe = find_executable(self.get_config_exe())
1947 if not config_exe:
1948 log.warn('File not found: %s. Cannot determine %s info.' \
1949 % (config_exe, self.section))
1950 return
1951 info = {}
1952 macros = []
1953 libraries = []
1954 library_dirs = []
1955 include_dirs = []
1956 extra_link_args = []
1957 extra_compile_args = []
1958 version = self.get_config_output(config_exe, self.version_flag)
1959 if version:
1960 macros.append((self.__class__.__name__.split('.')[-1].upper(),
1961 '"\\"%s\\""' % (version)))
1962 if self.version_macro_name:
1963 macros.append((self.version_macro_name + '_%s'
1964 % (version.replace('.', '_')), None))
1965 if self.release_macro_name:
1966 release = self.get_config_output(config_exe, '--release')
1967 if release:
1968 macros.append((self.release_macro_name + '_%s'
1969 % (release.replace('.', '_')), None))
1970 opts = self.get_config_output(config_exe, '--libs')
1971 if opts:
1972 for opt in opts.split():
1973 if opt[:2] == '-l':
1974 libraries.append(opt[2:])
1975 elif opt[:2] == '-L':
1976 library_dirs.append(opt[2:])
1977 else:
1978 extra_link_args.append(opt)
1979 opts = self.get_config_output(config_exe, self.cflags_flag)
1980 if opts:
1981 for opt in opts.split():
1982 if opt[:2] == '-I':
1983 include_dirs.append(opt[2:])
1984 elif opt[:2] == '-D':
1985 if '=' in opt:
1986 n, v = opt[2:].split('=')
1987 macros.append((n, v))
1988 else:
1989 macros.append((opt[2:], None))
1990 else:
1991 extra_compile_args.append(opt)
1992 if macros:
1993 dict_append(info, define_macros=macros)
1994 if libraries:
1995 dict_append(info, libraries=libraries)
1996 if library_dirs:
1997 dict_append(info, library_dirs=library_dirs)
1998 if include_dirs:
1999 dict_append(info, include_dirs=include_dirs)
2000 if extra_link_args:
2001 dict_append(info, extra_link_args=extra_link_args)
2002 if extra_compile_args:
2003 dict_append(info, extra_compile_args=extra_compile_args)
2004 if info:
2005 self.set_info(**info)
2006 return
2007
2008
2009 class wx_info(_pkg_config_info):
2010 section = 'wx'
2011 config_env_var = 'WX_CONFIG'
2012 default_config_exe = 'wx-config'
2013 append_config_exe = ''
2014 version_macro_name = 'WX_VERSION'
2015 release_macro_name = 'WX_RELEASE'
2016 version_flag = '--version'
2017 cflags_flag = '--cxxflags'
2018
2019
2020 class gdk_pixbuf_xlib_2_info(_pkg_config_info):
2021 section = 'gdk_pixbuf_xlib_2'
2022 append_config_exe = 'gdk-pixbuf-xlib-2.0'
2023 version_macro_name = 'GDK_PIXBUF_XLIB_VERSION'
2024
2025
2026 class gdk_pixbuf_2_info(_pkg_config_info):
2027 section = 'gdk_pixbuf_2'
2028 append_config_exe = 'gdk-pixbuf-2.0'
2029 version_macro_name = 'GDK_PIXBUF_VERSION'
2030
2031
2032 class gdk_x11_2_info(_pkg_config_info):
2033 section = 'gdk_x11_2'
2034 append_config_exe = 'gdk-x11-2.0'
2035 version_macro_name = 'GDK_X11_VERSION'
2036
2037
2038 class gdk_2_info(_pkg_config_info):
2039 section = 'gdk_2'
2040 append_config_exe = 'gdk-2.0'
2041 version_macro_name = 'GDK_VERSION'
2042
2043
2044 class gdk_info(_pkg_config_info):
2045 section = 'gdk'
2046 append_config_exe = 'gdk'
2047 version_macro_name = 'GDK_VERSION'
2048
2049
2050 class gtkp_x11_2_info(_pkg_config_info):
2051 section = 'gtkp_x11_2'
2052 append_config_exe = 'gtk+-x11-2.0'
2053 version_macro_name = 'GTK_X11_VERSION'
2054
2055
2056 class gtkp_2_info(_pkg_config_info):
2057 section = 'gtkp_2'
2058 append_config_exe = 'gtk+-2.0'
2059 version_macro_name = 'GTK_VERSION'
2060
2061
2062 class xft_info(_pkg_config_info):
2063 section = 'xft'
2064 append_config_exe = 'xft'
2065 version_macro_name = 'XFT_VERSION'
2066
2067
2068 class freetype2_info(_pkg_config_info):
2069 section = 'freetype2'
2070 append_config_exe = 'freetype2'
2071 version_macro_name = 'FREETYPE2_VERSION'
2072
2073
2074 class amd_info(system_info):
2075 section = 'amd'
2076 dir_env_var = 'AMD'
2077 _lib_names = ['amd']
2078
2079 def calc_info(self):
2080 lib_dirs = self.get_lib_dirs()
2081
2082 amd_libs = self.get_libs('amd_libs', self._lib_names)
2083 info = self.check_libs(lib_dirs, amd_libs, [])
2084 if info is None:
2085 return
2086
2087 include_dirs = self.get_include_dirs()
2088
2089 inc_dir = None
2090 for d in include_dirs:
2091 p = self.combine_paths(d, 'amd.h')
2092 if p:
2093 inc_dir = os.path.dirname(p[0])
2094 break
2095 if inc_dir is not None:
2096 dict_append(info, include_dirs=[inc_dir],
2097 define_macros=[('SCIPY_AMD_H', None)],
2098 swig_opts=['-I' + inc_dir])
2099
2100 self.set_info(**info)
2101 return
2102
2103
2104 class umfpack_info(system_info):
2105 section = 'umfpack'
2106 dir_env_var = 'UMFPACK'
2107 notfounderror = UmfpackNotFoundError
2108 _lib_names = ['umfpack']
2109
2110 def calc_info(self):
2111 lib_dirs = self.get_lib_dirs()
2112
2113 umfpack_libs = self.get_libs('umfpack_libs', self._lib_names)
2114 info = self.check_libs(lib_dirs, umfpack_libs, [])
2115 if info is None:
2116 return
2117
2118 include_dirs = self.get_include_dirs()
2119
2120 inc_dir = None
2121 for d in include_dirs:
2122 p = self.combine_paths(d, ['', 'umfpack'], 'umfpack.h')
2123 if p:
2124 inc_dir = os.path.dirname(p[0])
2125 break
2126 if inc_dir is not None:
2127 dict_append(info, include_dirs=[inc_dir],
2128 define_macros=[('SCIPY_UMFPACK_H', None)],
2129 swig_opts=['-I' + inc_dir])
2130
2131 amd = get_info('amd')
2132 dict_append(info, **get_info('amd'))
2133
2134 self.set_info(**info)
2135 return
2136
2137 ## def vstr2hex(version):
2138 ## bits = []
2139 ## n = [24,16,8,4,0]
2140 ## r = 0
2141 ## for s in version.split('.'):
2142 ## r |= int(s) << n[0]
2143 ## del n[0]
2144 ## return r
2145
2146 #--------------------------------------------------------------------
2147
2148
2149 def combine_paths(*args, **kws):
2150 """ Return a list of existing paths composed by all combinations of
2151 items from arguments.
2152 """
2153 r = []
2154 for a in args:
2155 if not a:
2156 continue
2157 if is_string(a):
2158 a = [a]
2159 r.append(a)
2160 args = r
2161 if not args:
2162 return []
2163 if len(args) == 1:
2164 result = reduce(lambda a, b: a + b, map(glob, args[0]), [])
2165 elif len(args) == 2:
2166 result = []
2167 for a0 in args[0]:
2168 for a1 in args[1]:
2169 result.extend(glob(os.path.join(a0, a1)))
2170 else:
2171 result = combine_paths(*(combine_paths(args[0], args[1]) + args[2:]))
2172 verbosity = kws.get('verbosity', 1)
2173 log.debug('(paths: %s)', ','.join(result))
2174 return result
2175
2176 language_map = {'c': 0, 'c++': 1, 'f77': 2, 'f90': 3}
2177 inv_language_map = {0: 'c', 1: 'c++', 2: 'f77', 3: 'f90'}
2178
2179
2180 def dict_append(d, **kws):
2181 languages = []
2182 for k, v in kws.items():
2183 if k == 'language':
2184 languages.append(v)
2185 continue
2186 if k in d:
2187 if k in ['library_dirs', 'include_dirs', 'define_macros']:
2188 [d[k].append(vv) for vv in v if vv not in d[k]]
2189 else:
2190 d[k].extend(v)
2191 else:
2192 d[k] = v
2193 if languages:
2194 l = inv_language_map[max([language_map.get(l, 0) for l in languages])]
2195 d['language'] = l
2196 return
2197
2198
2199 def parseCmdLine(argv=(None,)):
2200 import optparse
2201 parser = optparse.OptionParser("usage: %prog [-v] [info objs]")
2202 parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
2203 default=False,
2204 help='be verbose and print more messages')
2205
2206 opts, args = parser.parse_args(args=argv[1:])
2207 return opts, args
2208
2209
2210 def show_all(argv=None):
2211 import inspect
2212 if argv is None:
2213 argv = sys.argv
2214 opts, args = parseCmdLine(argv)
2215 if opts.verbose:
2216 log.set_threshold(log.DEBUG)
2217 else:
2218 log.set_threshold(log.INFO)
2219 show_only = []
2220 for n in args:
2221 if n[-5:] != '_info':
2222 n = n + '_info'
2223 show_only.append(n)
2224 show_all = not show_only
2225 _gdict_ = globals().copy()
2226 for name, c in _gdict_.items():
2227 if not inspect.isclass(c):
2228 continue
2229 if not issubclass(c, system_info) or c is system_info:
2230 continue
2231 if not show_all:
2232 if name not in show_only:
2233 continue
2234 del show_only[show_only.index(name)]
2235 conf = c()
2236 conf.verbosity = 2
2237 r = conf.get_info()
2238 if show_only:
2239 log.info('Info classes not defined: %s', ','.join(show_only))
2240
2241 if __name__ == "__main__":
2242 show_all()