87 lines
2.9 KiB
Python
87 lines
2.9 KiB
Python
|
import sys
|
||
|
import os
|
||
|
from distutils.version import LooseVersion
|
||
|
from multiprocessing import cpu_count
|
||
|
|
||
|
CYTHON_VERSION = '0.23.4'
|
||
|
|
||
|
# WindowsError is not defined on unix systems
|
||
|
try:
|
||
|
WindowsError
|
||
|
except NameError:
|
||
|
class WindowsError(Exception):
|
||
|
pass
|
||
|
|
||
|
|
||
|
def _compiled_filename(f):
|
||
|
"""Check for the presence of a .pyx[.in] file as a .c or .cpp."""
|
||
|
basename = f.replace('.in', '').replace('.pyx', '')
|
||
|
for ext in ('.c', '.cpp'):
|
||
|
filename = basename + ext
|
||
|
if os.path.exists(filename):
|
||
|
return filename
|
||
|
else:
|
||
|
raise RuntimeError('Cython >= %s is required to build '
|
||
|
'scikit-image from git checkout' %
|
||
|
CYTHON_VERSION)
|
||
|
|
||
|
|
||
|
def cython(pyx_files, working_path=''):
|
||
|
"""Use Cython to convert the given files to C.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
pyx_files : list of str
|
||
|
The input .pyx files.
|
||
|
|
||
|
"""
|
||
|
# Do not build cython files if target is clean
|
||
|
if len(sys.argv) >= 2 and sys.argv[1] == 'clean':
|
||
|
return
|
||
|
|
||
|
try:
|
||
|
from Cython import __version__
|
||
|
if LooseVersion(__version__) < CYTHON_VERSION:
|
||
|
raise RuntimeError('Cython >= %s needed to build scikit-image' % CYTHON_VERSION)
|
||
|
|
||
|
from Cython.Build import cythonize
|
||
|
except ImportError:
|
||
|
# If cython is not found, the build will make use of
|
||
|
# the distributed .c or .cpp files if present
|
||
|
c_files_used = [_compiled_filename(os.path.join(working_path, f))
|
||
|
for f in pyx_files]
|
||
|
|
||
|
print("Cython >= %s not found; falling back to pre-built %s" \
|
||
|
% (CYTHON_VERSION, " ".join(c_files_used)))
|
||
|
else:
|
||
|
pyx_files = [os.path.join(working_path, f) for f in pyx_files]
|
||
|
for i, pyxfile in enumerate(pyx_files):
|
||
|
if pyxfile.endswith('.pyx.in'):
|
||
|
process_tempita_pyx(pyxfile)
|
||
|
pyx_files[i] = pyxfile.replace('.pyx.in', '.pyx')
|
||
|
|
||
|
# Cython doesn't automatically choose a number of threads > 1
|
||
|
# https://github.com/cython/cython/blob/a0bbb940c847dfe92cac446c8784c34c28c92836/Cython/Build/Dependencies.py#L923-L925
|
||
|
cythonize(pyx_files, nthreads=cpu_count(),
|
||
|
compiler_directives={'language_level': 3})
|
||
|
|
||
|
|
||
|
def process_tempita_pyx(fromfile):
|
||
|
try:
|
||
|
try:
|
||
|
from Cython import Tempita as tempita
|
||
|
except ImportError:
|
||
|
import tempita
|
||
|
except ImportError:
|
||
|
raise Exception('Building requires Tempita: '
|
||
|
'pip install --user Tempita')
|
||
|
template = tempita.Template.from_filename(fromfile,
|
||
|
encoding=sys.getdefaultencoding())
|
||
|
pyxcontent = template.substitute()
|
||
|
if not fromfile.endswith('.pyx.in'):
|
||
|
raise ValueError("Unexpected extension of %s." % fromfile)
|
||
|
|
||
|
pyxfile = os.path.splitext(fromfile)[0] # split off the .in ending
|
||
|
with open(pyxfile, "w") as f:
|
||
|
f.write(pyxcontent)
|