Skip to content
Snippets Groups Projects
Commit e9b66cd3 authored by Andreas Klöckner's avatar Andreas Klöckner
Browse files

Allow setup_requires numpy, use pybind11 setup widgetry from aksetup

parent af56ea99
No related branches found
No related tags found
No related merge requests found
import setuptools # noqa import setuptools # noqa
from setuptools import Extension from setuptools import Extension
import sys import sys
from setuptools.command.build_ext import ( # noqa: N812
build_ext as BaseBuildExtCommand)
def count_down_delay(delay): def count_down_delay(delay):
...@@ -32,6 +34,14 @@ def setup(*args, **kwargs): ...@@ -32,6 +34,14 @@ def setup(*args, **kwargs):
raise raise
def get_numpy_incpath():
from imp import find_module
# avoid actually importing numpy, it screws up distutils
file, pathname, descr = find_module("numpy")
from os.path import join
return join(pathname, "core", "include")
class NumpyExtension(Extension): class NumpyExtension(Extension):
# nicked from # nicked from
# http://mail.python.org/pipermail/distutils-sig/2007-September/008253.html # http://mail.python.org/pipermail/distutils-sig/2007-September/008253.html
...@@ -41,15 +51,8 @@ class NumpyExtension(Extension): ...@@ -41,15 +51,8 @@ class NumpyExtension(Extension):
self._include_dirs = self.include_dirs self._include_dirs = self.include_dirs
del self.include_dirs # restore overwritten property del self.include_dirs # restore overwritten property
def get_numpy_incpath(self):
from imp import find_module
# avoid actually importing numpy, it screws up distutils
file, pathname, descr = find_module("numpy")
from os.path import join
return join(pathname, "core", "include")
def get_additional_include_dirs(self): def get_additional_include_dirs(self):
return [self.get_numpy_incpath()] return [get_numpy_incpath()]
def get_include_dirs(self): def get_include_dirs(self):
return self._include_dirs + self.get_additional_include_dirs() return self._include_dirs + self.get_additional_include_dirs()
...@@ -63,35 +66,44 @@ class NumpyExtension(Extension): ...@@ -63,35 +66,44 @@ class NumpyExtension(Extension):
include_dirs = property(get_include_dirs, set_include_dirs, del_include_dirs) include_dirs = property(get_include_dirs, set_include_dirs, del_include_dirs)
class PyUblasExtension(NumpyExtension): class ExtensionUsingNumpy(Extension):
def get_module_include_path(self, name): """Unlike :class:`NumpyExtension`, this class does not require numpy to be
from pkg_resources import Requirement, resource_filename importable upon extension module creation, allowing ``setup_requires=["numpy"]``
return resource_filename(Requirement.parse(name), "%s/include" % name) to work. On the other hand, it requires the use of::
def get_additional_include_dirs(self): setup(...,
return (NumpyExtension.get_additional_include_dirs(self) cmdclass={'build_ext': NumpyBuildExtCommand})
+ [self.get_module_include_path("pyublas")])
or
setup(...,
cmdclass={'build_ext': PybindBuildExtCommand})
"""
class NumpyBuildExtCommand(BaseBuildExtCommand):
def build_extension(self, extension):
# We add the numpy include dir right before building the
# extension, in order to avoid having to import numpy when
# the setup script is imported, which would prevent
# installation before manual installation of numpy.
if isinstance(extension, ExtensionUsingNumpy):
numpy_incpath = get_numpy_incpath()
if numpy_incpath not in extension.include_dirs:
extension.include_dirs.append(numpy_incpath)
class HedgeExtension(PyUblasExtension): super(NumpyBuildExtCommand, self).build_extension(extension)
@property
def include_dirs(self):
return self._include_dirs + [
self.get_numpy_incpath(),
self.get_module_include_path("pyublas"),
self.get_module_include_path("hedge"),
]
# {{{ tools # {{{ tools
def flatten(list): def flatten(lst):
"""For an iterable of sub-iterables, generate each member of each """For an iterable of sub-iterables, generate each member of each
sub-iterable in turn, i.e. a flattened version of that super-iterable. sub-iterable in turn, i.e. a flattened version of that super-iterable.
Example: Turn [[a,b,c],[d,e,f]] into [a,b,c,d,e,f]. Example: Turn [[a,b,c],[d,e,f]] into [a,b,c,d,e,f].
""" """
for sublist in list: for sublist in lst:
for j in sublist: for j in sublist:
yield j yield j
...@@ -504,6 +516,10 @@ class Libraries(StringListOption): ...@@ -504,6 +516,10 @@ class Libraries(StringListOption):
help=help or ("Library names for %s (without lib or .so)" help=help or ("Library names for %s (without lib or .so)"
% (human_name or humanize(lib_name)))) % (human_name or humanize(lib_name))))
# }}}
# {{{ configure options for specific software
class BoostLibraries(Libraries): class BoostLibraries(Libraries):
def __init__(self, lib_base_name, default_lib_name=None): def __init__(self, lib_base_name, default_lib_name=None):
...@@ -628,6 +644,10 @@ def make_boost_base_options(): ...@@ -628,6 +644,10 @@ def make_boost_base_options():
help="The compiler with which Boost C++ was compiled, e.g. gcc43"), help="The compiler with which Boost C++ was compiled, e.g. gcc43"),
] ]
# }}}
# {{{ configure frontend
def configure_frontend(): def configure_frontend():
from optparse import OptionParser from optparse import OptionParser
...@@ -679,6 +699,8 @@ def configure_frontend(): ...@@ -679,6 +699,8 @@ def configure_frontend():
substitute(substs, "Makefile") substitute(substs, "Makefile")
# }}}
def substitute(substitutions, fname): def substitute(substitutions, fname):
import re import re
...@@ -723,6 +745,8 @@ def substitute(substitutions, fname): ...@@ -723,6 +745,8 @@ def substitute(substitutions, fname):
chmod(fname, infile_stat_res.st_mode) chmod(fname, infile_stat_res.st_mode)
# {{{ git bits
def _run_git_command(cmd): def _run_git_command(cmd):
git_error = None git_error = None
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
...@@ -828,6 +852,10 @@ def check_git_submodules(): ...@@ -828,6 +852,10 @@ def check_git_submodules():
print("git submodules initialized successfully") print("git submodules initialized successfully")
print(DASH_SEPARATOR) print(DASH_SEPARATOR)
# }}}
# {{{ pybind11
def check_pybind11(): def check_pybind11():
try: try:
...@@ -848,3 +876,83 @@ def check_pybind11(): ...@@ -848,3 +876,83 @@ def check_pybind11():
from aksetup_helper import count_down_delay from aksetup_helper import count_down_delay
count_down_delay(delay=10) count_down_delay(delay=10)
# {{{ boilerplate from https://github.com/pybind/python_example/blob/2ed5a68759cd6ff5d2e5992a91f08616ef457b5c/setup.py # noqa
class get_pybind_include(object): # noqa: N801
"""Helper class to determine the pybind11 include path
The purpose of this class is to postpone importing pybind11
until it is actually installed, so that the ``get_include()``
method can be invoked. """
def __init__(self, user=False):
self.user = user
def __str__(self):
import pybind11
return pybind11.get_include(self.user)
# As of Python 3.6, CCompiler has a `has_flag` method.
# cf http://bugs.python.org/issue26689
def has_flag(compiler, flagname):
"""Return a boolean indicating whether a flag name is supported on
the specified compiler.
"""
import tempfile
with tempfile.NamedTemporaryFile('w', suffix='.cpp', delete=False) as f:
f.write('int main (int argc, char **argv) { return 0; }')
fname = f.name
try:
compiler.compile([fname], extra_postargs=[flagname])
except setuptools.distutils.errors.CompileError:
return False
return True
def cpp_flag(compiler):
"""Return the -std=c++[11/14] compiler flag.
The c++14 is prefered over c++11 (when it is available).
"""
if has_flag(compiler, '-std=c++14'):
return '-std=c++14'
elif has_flag(compiler, '-std=c++11'):
return '-std=c++11'
else:
raise RuntimeError('Unsupported compiler -- at least C++11 support '
'is needed!')
class PybindBuildExtCommand(NumpyBuildExtCommand):
"""A custom build extension for adding compiler-specific options."""
c_opts = {
'msvc': ['/EHsc'],
'unix': [],
}
if sys.platform == 'darwin':
c_opts['unix'] += ['-stdlib=libc++', '-mmacosx-version-min=10.7']
def build_extensions(self):
ct = self.compiler.compiler_type
opts = self.c_opts.get(ct, [])
if ct in ['unix', 'mingw32']:
opts.append('-DVERSION_INFO="%s"' % self.distribution.get_version())
opts.append(cpp_flag(self.compiler))
if has_flag(self.compiler, '-fvisibility=hidden'):
opts.append('-fvisibility=hidden')
elif ct == 'msvc':
opts.append('/DVERSION_INFO=\\"%s\\"' % self.distribution.get_version())
for ext in self.extensions:
ext.extra_compile_args = ext.extra_compile_args + opts
super(PybindBuildExtCommand, self).build_extensions()
# }}}
# }}}
# vim: foldmethod=marker
...@@ -31,89 +31,12 @@ THE SOFTWARE. ...@@ -31,89 +31,12 @@ THE SOFTWARE.
import sys import sys
from os.path import exists from os.path import exists
import setuptools
from setuptools.command.build_ext import build_ext
# {{{ boilerplate from https://github.com/pybind/python_example/blob/2ed5a68759cd6ff5d2e5992a91f08616ef457b5c/setup.py # noqa
class get_pybind_include(object): # noqa: N801
"""Helper class to determine the pybind11 include path
The purpose of this class is to postpone importing pybind11
until it is actually installed, so that the ``get_include()``
method can be invoked. """
def __init__(self, user=False):
self.user = user
def __str__(self):
import pybind11
return pybind11.get_include(self.user)
# As of Python 3.6, CCompiler has a `has_flag` method.
# cf http://bugs.python.org/issue26689
def has_flag(compiler, flagname):
"""Return a boolean indicating whether a flag name is supported on
the specified compiler.
"""
import tempfile
with tempfile.NamedTemporaryFile('w', suffix='.cpp', delete=False) as f:
f.write('int main (int argc, char **argv) { return 0; }')
fname = f.name
try:
compiler.compile([fname], extra_postargs=[flagname])
except setuptools.distutils.errors.CompileError:
return False
return True
def cpp_flag(compiler):
"""Return the -std=c++[11/14] compiler flag.
The c++14 is prefered over c++11 (when it is available).
"""
if has_flag(compiler, '-std=c++14'):
return '-std=c++14'
elif has_flag(compiler, '-std=c++11'):
return '-std=c++11'
else:
raise RuntimeError('Unsupported compiler -- at least C++11 support '
'is needed!')
class BuildExt(build_ext):
"""A custom build extension for adding compiler-specific options."""
c_opts = {
'msvc': ['/EHsc'],
'unix': [],
}
if sys.platform == 'darwin':
c_opts['unix'] += ['-stdlib=libc++', '-mmacosx-version-min=10.7']
def build_extensions(self):
ct = self.compiler.compiler_type
opts = self.c_opts.get(ct, [])
if ct in ['unix', 'mingw32']:
opts.append('-DVERSION_INFO="%s"' % self.distribution.get_version())
opts.append(cpp_flag(self.compiler))
if has_flag(self.compiler, '-fvisibility=hidden'):
opts.append('-fvisibility=hidden')
elif ct == 'msvc':
opts.append('/DVERSION_INFO=\\"%s\\"' % self.distribution.get_version())
for ext in self.extensions:
ext.extra_compile_args = ext.extra_compile_args + opts
build_ext.build_extensions(self)
# }}}
def get_config_schema(): def get_config_schema():
from aksetup_helper import ConfigSchema, Option, \ from aksetup_helper import (ConfigSchema, Option,
IncludeDir, LibraryDir, Libraries, \ IncludeDir, LibraryDir, Libraries,
Switch, StringListOption Switch, StringListOption)
default_cxxflags = [ default_cxxflags = [
# Required for pybind11: # Required for pybind11:
...@@ -184,7 +107,8 @@ SEPARATOR = "-"*75 ...@@ -184,7 +107,8 @@ SEPARATOR = "-"*75
def main(): def main():
from setuptools import find_packages from setuptools import find_packages
from aksetup_helper import (hack_distutils, get_config, setup, from aksetup_helper import (hack_distutils, get_config, setup,
check_pybind11, check_git_submodules, NumpyExtension) check_pybind11, check_git_submodules, ExtensionUsingNumpy,
get_pybind_include, PybindBuildExtCommand)
check_pybind11() check_pybind11()
check_git_submodules() check_git_submodules()
...@@ -299,7 +223,7 @@ def main(): ...@@ -299,7 +223,7 @@ def main():
packages=find_packages(), packages=find_packages(),
ext_modules=[ ext_modules=[
NumpyExtension("pyopencl._cl", ExtensionUsingNumpy("pyopencl._cl",
[ [
"src/wrap_constants.cpp", "src/wrap_constants.cpp",
"src/wrap_cl.cpp", "src/wrap_cl.cpp",
...@@ -345,7 +269,7 @@ def main(): ...@@ -345,7 +269,7 @@ def main():
] ]
}, },
cmdclass={'build_ext': BuildExt}, cmdclass={'build_ext': PybindBuildExtCommand},
zip_safe=False) zip_safe=False)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment