Skip to content

Commit

Permalink
[setup] fix temporary install of pybind in direct invocation of setup.py
Browse files Browse the repository at this point in the history
  • Loading branch information
marscher committed Sep 14, 2018
1 parent 59b96e9 commit 8e8b70a
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 4 deletions.
8 changes: 4 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
import warnings
from io import open

from setup_util import lazy_cythonize
from setup_util import lazy_cythonize, get_pybind_include

try:
from setuptools import setup, Extension, find_packages
Expand Down Expand Up @@ -104,9 +104,9 @@ def extensions():
import mdtraj
from numpy import get_include as _np_inc
np_inc = _np_inc()
import pybind11
pybind_inc = pybind11.get_include()
assert os.path.exists(pybind_inc)

pybind_inc = get_pybind_include()
assert os.path.exists(os.path.join(pybind_inc, 'pybind11', 'pybind11.h'))

exts = []
lib_prefix = 'lib' if sys.platform.startswith('win') else ''
Expand Down
59 changes: 59 additions & 0 deletions setup_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,62 @@ def __iter__(self):
for e in self.c_list(): yield e
def __getitem__(self, ii): return self.c_list()[ii]
def __len__(self): return len(self.c_list())


class get_pybind_include(object):
"""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 search_pybind11_headers(self):
import pybind11

def recommended():
return pybind11.get_include(self.user)

def setuptools_temp_egg():
# If users of setuptools drag in pybind11 only as a setup_require(ment), the pkg will be placed
# temporarily into .eggs, but we can not use the headers directly. So we have to
# link non-installed header files to correct subdirectory, so they can be used during compilation
found = False
for p in pybind11.__path__:
if '.egg' in p:
found = True
if not found:
return ''

header_src = os.path.abspath(os.path.join(pybind11.__path__[0], '..'))
hdrs = []

for _, _, filenames in os.walk(header_src):
hdrs += [f for f in filenames if f.endswith('.h')]
for h in sorted(hdrs):
if 'detail' in h:
sub = 'detail'
else:
sub = ''
dest = os.path.join(pybind11.__path__[0], sub, os.path.basename(h))
try:
os.link(h, dest)
except OSError:
pass
return header_src

methods = (recommended(),
setuptools_temp_egg(),
)
for m in methods:
if os.path.exists(os.path.join(m, 'pybind11', 'pybind11.h')):
return m
return ''

def __str__(self):
result = self.search_pybind11_headers()
if not result:
raise RuntimeError()
return result

0 comments on commit 8e8b70a

Please sign in to comment.