Skip to content

Commit

Permalink
Merge pull request #220 from mdpearson/darwin-pip
Browse files Browse the repository at this point in the history
Update cy_build.py to support pip and develop mode on Mac.
  • Loading branch information
AndreasHeger committed Feb 5, 2016
2 parents 472daa3 + f6a7616 commit 915c213
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 29 deletions.
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ include htslib/config.h.in
include htslib/htslib/*.h
include htslib/cram/*.c
include htslib/cram/*.h
include cy_build.py
include pysam.py
include requirements.txt

# pysam tests
include tests/00README.txt
Expand Down
72 changes: 46 additions & 26 deletions cy_build.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
import os
import re
import sys

from distutils.sysconfig import get_config_vars, get_python_lib, get_python_version
from Cython.Distutils import build_ext
from distutils.extension import Extension
from distutils.sysconfig import get_config_vars, get_python_lib, get_python_version
from pkg_resources import Distribution
from Cython.Distutils import build_ext


if sys.platform == 'darwin':
config_vars = get_config_vars()
#config_vars['SO'] = '.dylib'
config_vars['LDSHARED'] = config_vars['LDSHARED'].replace('-bundle', '-Wl,-x')
config_vars['LDSHARED'] = config_vars['LDSHARED'].replace('-bundle', '')
config_vars['SHLIB_EXT'] = '.so'
config_vars['SO'] = '.so'


class CyExtension(Extension):
def __init__(self, name, sources, include_dirs=None, define_macros=None, undef_macros=None, library_dirs=None,
libraries=None, runtime_library_dirs=None, extra_objects=None, extra_compile_args=None, extra_link_args=None,
export_symbols=None, swig_opts=None, depends=None, language=None, init_func=None, **kw):
def is_pip_install():
if "_" in os.environ and os.environ["_"].endswith("pip"):
return True
if "pip-egg-info" in sys.argv:
return True
if re.search("/pip-.*-build/", __file__):
return True
return False

self._init_func = init_func

Extension.__init__(self, name, sources, include_dirs, define_macros, undef_macros, library_dirs, libraries,
runtime_library_dirs, extra_objects, extra_compile_args, extra_link_args, export_symbols,
swig_opts, depends, language, **kw)
class CyExtension(Extension):
def __init__(self, *args, **kwargs):
self._init_func = kwargs.pop("init_func", None)
Extension.__init__(self, *args, **kwargs)

def extend_includes(self, includes):
self.include_dirs.extend(includes)
Expand All @@ -34,25 +41,38 @@ def extend_extra_objects(self, objs):


class cy_build_ext(build_ext):

def _get_egg_name(self):
ei_cmd = self.get_finalized_command("egg_info")
return Distribution(None, None, ei_cmd.egg_name, ei_cmd.egg_version, get_python_version(),
self.distribution.has_ext_modules() and self.plat_name).egg_name()

def build_extension(self, ext):
if isinstance(ext, CyExtension) and ext._init_func:
ext._init_func(ext)

if sys.platform == 'darwin':
ext.extra_link_args = ext.extra_link_args or []

egg_name = '%s.egg' % self._get_egg_name()
name = ext.name
install_name = '%s/%s/%s%s' % (get_python_lib(), egg_name, name.replace('.', os.sep), config_vars['SO'])

extra = ['-dynamiclib', '-undefined', 'dynamic_lookup', '-shared',
'-Wl,-headerpad_max_install_names', '-Wl,-install_name,%s' % install_name]

ext.extra_link_args += extra
relative_module_path = ext.name.replace(".", os.sep) + get_config_vars()["SO"]

if "develop" in sys.argv or "test" in sys.argv:
# develop-mode and tests use local directory
pkg_root = os.path.dirname(__file__)
linker_path = os.path.join(pkg_root, relative_module_path)
elif "bdist_wheel" in sys.argv or is_pip_install():
# making a wheel, or pip is secretly involved
linker_path = os.path.join("@rpath", relative_module_path)
else:
# making an egg: `python setup.py install` default behavior
egg_name = '%s.egg' % self._get_egg_name()
linker_path = os.path.join("@rpath", egg_name, relative_module_path)

if not ext.extra_link_args:
ext.extra_link_args = []
ext.extra_link_args += ['-dynamiclib',
'-rpath', get_python_lib(),
'-Wl,-headerpad_max_install_names',
'-Wl,-install_name,%s' % linker_path,
'-Wl,-x']

build_ext.build_extension(self, ext)

def _get_egg_name(self):
ei_cmd = self.get_finalized_command("egg_info")
return Distribution(None, None, ei_cmd.egg_name, ei_cmd.egg_version, get_python_version(),
self.distribution.has_ext_modules() and self.plat_name).egg_name()
23 changes: 20 additions & 3 deletions pysam/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,26 @@
def get_include():
'''return a list of include directories.'''
dirname = os.path.abspath(os.path.join(os.path.dirname(__file__)))
return [dirname,
os.path.join(dirname, 'include', 'htslib'),
os.path.join(dirname, 'include', 'samtools')]

#
# Header files may be stored in different relative locations
# depending on installation mode (e.g., `python setup.py install`,
# `python setup.py develop`. The first entry in each list is
# where develop-mode headers can be found.
#
htslib_possibilities = [os.path.join(dirname, '..', 'htslib'),
os.path.join(dirname, 'include', 'htslib')]
samtool_possibilities = [os.path.join(dirname, '..', 'samtools'),
os.path.join(dirname, 'include', 'samtools')]

includes = [dirname]
for header_locations in [htslib_possibilities, samtool_possibilities]:
for header_location in header_locations:
if os.path.exists(header_location):
includes.append(os.path.abspath(header_location))
break

return includes


def get_defines():
Expand Down

0 comments on commit 915c213

Please sign in to comment.