1#!/usr/bin/env python 2 3import sys 4import setuptools 5from setuptools import setup, Extension 6from setuptools.command.build_ext import build_ext 7from git_version import git_version 8 9class get_pybind_include(object): 10 """Helper class to determine the pybind11 include path 11 12 The purpose of this class is to postpone importing pybind11 13 until it is actually installed, so that the ``get_include()`` 14 method can be invoked. """ 15 16 def __init__(self, user=False): 17 self.user = user 18 19 def __str__(self): 20 import pybind11 21 return pybind11.get_include(self.user) 22 23 24# As of Python 3.6, CCompiler has a `has_flag` method. 25# cf http://bugs.python.org/issue26689 26def has_flag(compiler, flagname): 27 """Return a boolean indicating whether a flag name is supported on 28 the specified compiler. 29 """ 30 import tempfile 31 with tempfile.NamedTemporaryFile('w', suffix='.cpp') as f: 32 f.write('int main (int argc, char **argv) { return 0; }') 33 try: 34 compiler.compile([f.name], extra_postargs=[flagname]) 35 except setuptools.distutils.errors.CompileError: 36 return False 37 return True 38 39 40def cpp_flag(compiler): 41 """Return the -std=c++[11/14] compiler flag. 42 43 The c++14 is prefered over c++11 (when it is available). 44 """ 45 if has_flag(compiler, '-std=c++14'): 46 return '-std=c++14' 47 elif has_flag(compiler, '-std=c++11'): 48 return '-std=c++11' 49 else: 50 raise RuntimeError('Unsupported compiler -- at least C++11 support ' 51 'is needed!') 52 53 54class BuildExt(build_ext): 55 """A custom build extension for adding compiler-specific options.""" 56 c_opts = { 57 'msvc': ['/EHsc'], 58 'unix': [], 59 } 60 61 if sys.platform == 'darwin': 62 c_opts['unix'] += ['-stdlib=libc++', '-mmacosx-version-min=10.7'] 63 64 def build_extensions(self): 65 ct = self.compiler.compiler_type 66 opts = self.c_opts.get(ct, []) 67 link_args = [] 68 69 if ct == 'unix': 70 opts.append('-DVERSION_INFO="%s"' % self.distribution.get_version()) 71 opts.append(cpp_flag(self.compiler)) 72 if has_flag(self.compiler, '-fvisibility=hidden'): 73 opts.append('-fvisibility=hidden') 74 elif ct == 'msvc': 75 opts.append('/DVERSION_INFO=\\"%s\\"' % self.distribution.get_version()) 76 77 if has_flag(self.compiler, '-fopenmp'): 78 opts.append('-fopenmp') 79 link_args.append('-fopenmp') 80 elif has_flag(self.compiler, '-openmp'): 81 opts.append('-openmp') 82 link_args.append('-openmp') 83 84 for ext in self.extensions: 85 ext.extra_compile_args = opts 86 ext.extra_link_args = link_args 87 88 build_ext.build_extensions(self) 89 90 91setup( 92 name='pyamgcl', 93 version=git_version(), 94 description='Solution of large sparse linear systems with Algebraic Multigrid Method', 95 author='Denis Demidov', 96 author_email='dennis.demidov@gmail.com', 97 license='MIT', 98 url='https://github.com/ddemidov/amgcl', 99 packages=['pyamgcl'], 100 include_package_data=True, 101 exclude_package_data={'': ['CMakeLists.txt', 'pybind11']}, 102 zip_safe=False, 103 ext_modules=[ 104 Extension('pyamgcl.pyamgcl_ext', ['pyamgcl/pyamgcl.cpp'], 105 include_dirs=[ 106 '.', 107 get_pybind_include(), 108 get_pybind_include(user=True) 109 ], 110 language='c++' 111 ) 112 ], 113 install_requires=['pybind11>=1.7'], 114 cmdclass={'build_ext': BuildExt}, 115) 116