forked from antocuni/capnpy
-
Notifications
You must be signed in to change notification settings - Fork 7
/
setup.py
191 lines (157 loc) · 6.38 KB
/
setup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
import sys
import os
from setuptools import setup, find_packages, Extension
from setuptools.command.sdist import sdist
try:
from Cython.Distutils import build_ext
except ImportError:
from setuptools.command.build_ext import build_ext
"""
In the following, we speak about Cython being required or not: we are
talking about "setup.py-time requirements", i.e. if Cython needs to be
installed **before** trying to install capnpy. Once the setup.py is running,
Cython will always be installed transparently because it's listed in
`install_requires`.
The following applies only to CPython; Cython is never required on PyPy.
There are various use-cases to consider:
1. manual `setup.py sdist`: the custom command my_sdist make sure to
generate the C files and include them in the .tar.gz. Cython is REQUIRED.
2. manual install from the sdist tarball: it will use already-generated C
files. Cython is NOT required.
3. manual install from a git checkout: the C files will NOT be there; the
custom command my_build_ext will take care of generate them
automatically. Cython is REQUIRED.
4. 'pip install capnpy': in most cases it will download a prebuilt binary
wheel from pypi; in the others, it will build from the sdist. In both
cases, Cython is NOT required.
5. 'pip install git+http://github.com/...': pip will first install Cython
(because it's in install_requires), then install capnpy (and since Cython
is installed, the C files will be automatically generated). Thus, Cython
is handled completely transparently.
So, Cython is handled transparently in cases (4) and (5), which are the two
most common ones.
In theory, we could add 'cython>=0.25' to setup_requires. This way, Cython
will be handled transparently also in the remaining cases. However:
- if we do this setuptools tries to install cython in *all* cases
- this installation is done by setuptools/easy_install, NOT pip
- setuptools does not support installing from wheels; the result is that it
tries to compile Cython, which is slow
- this make cases (4) and (5) considerably slower than needed, because pip
will be forced to wait for setuptools to compile cython, instead of doing
a fast install from a wheel.
So, we chose to speed up the common cases, at the cost of requiring an
explicit installation of Cython in the non common cases (1) and (3).
"""
###############################################################################
# Custom distutils commands
def my_cythonize(extensions):
try:
import Cython
if Cython.__version__ < '0.25':
print ('WARNING: required cython>0.25, found %s. The .c files will '
'NOT be regenerated' % Cython.__version__)
raise ImportError
from Cython.Build import cythonize
except ImportError:
return cythonize_dummy(extensions)
else:
return cythonize(extensions, gdb_debug=DEBUG)
def cythonize_dummy(extensions):
def cname(fname):
return fname.replace('.pyx', '.c').replace('.py', '.c')
#
for ext in extensions:
ext.sources = [cname(s) for s in ext.sources]
for src in ext.sources:
if not os.path.exists(src):
print ('%s does not exist and Cython is not installed. '
'Please install Cython to regenerate it '
'automatically.' % src)
sys.exit(1)
return extensions
class my_sdist(sdist):
"""
Same as the standard sdist, but make sure to cythonize the files first.
"""
def run(self):
my_cythonize(self.distribution.ext_modules)
return sdist.run(self)
class my_build_ext(build_ext):
"""
Same as the standard build_ext, but tries to handle cythonize as much
transparently as possible. In particular, if Cython is not installed, it
tries to reuse the existing *.c files which were included in the sdist.
"""
def build_extensions(self):
self.extensions = my_cythonize(self.extensions)
return build_ext.build_extensions(self)
# end of the custom commands section
###############################################################################
DEBUG = int(os.environ.get('CAPNPY_DEBUG', False)) # whether to compile files with -g
def get_cython_extensions():
files = ["capnpy/segment/base.pyx",
"capnpy/segment/segment.py",
"capnpy/segment/builder.pyx",
"capnpy/segment/endof.py",
"capnpy/blob.py",
"capnpy/enum.py",
"capnpy/struct_.py",
"capnpy/list.py",
"capnpy/type.py",
"capnpy/message.py",
"capnpy/buffered.py",
"capnpy/filelike.py",
"capnpy/ptr.pyx",
"capnpy/packing.pyx",
"capnpy/_hash.pyx",
"capnpy/_util.pyx"
]
root_dir = os.path.abspath(os.path.dirname(__file__))
capnpy_dir = os.path.join(root_dir, 'capnpy')
def getext(fname):
extname = fname.replace('/', '.').replace('.pyx', '').replace('.py', '')
if DEBUG:
extra_compile_args = ['-O0', '-g']
else:
extra_compile_args = ['-O3']
return Extension(
extname,
[fname],
include_dirs = [capnpy_dir],
extra_compile_args = extra_compile_args,
)
return [getext(f) for f in files]
if hasattr(sys, 'pypy_version_info'):
# on PyPy
USE_CYTHON = False
else:
# on CPython
USE_CYTHON = int(os.environ.get('USE_CYTHON', True))
if USE_CYTHON:
ext_modules = get_cython_extensions()
extra_install_requires = ['cython>=0.25']
else:
ext_modules = []
extra_install_requires = []
setup(name="capnpy",
author='Antonio Cuni',
author_email='[email protected]',
url='https://github.com/antocuni/capnpy',
use_scm_version=True,
include_package_data=True,
cmdclass={
'sdist': my_sdist,
'build_ext': my_build_ext,
},
packages=find_packages(),
ext_modules=ext_modules,
install_requires=['pypytools>=0.3.3', 'docopt', 'six'] + extra_install_requires,
setup_requires=['setuptools_scm'],
zip_safe=False,
entry_points={
"distutils.setup_keywords": [
"capnpy_options = capnpy.compiler.distutils:capnpy_options",
"capnpy_schemas = capnpy.compiler.distutils:capnpy_schemas",
],
}
)