setup.py: optionally build cython extension
If Cython is already pre-installed, we opportunistically try to compile the cu2qu extension module, and if it fails (e.g. compiler is not available), then we silently fall back to pure-python mode. If user explicitly requests --with-cython (or sets 'FONTTOOLS_WITH_CYTHON=1' env variable), then we add cython to setup_requires, and raise an error if compilation fails.
This commit is contained in:
parent
84b06022ed
commit
c327dc6f0d
107
setup.py
107
setup.py
@ -6,7 +6,8 @@ import sys
|
||||
import os
|
||||
from os.path import isfile, join as pjoin
|
||||
from glob import glob
|
||||
from setuptools import setup, find_packages, Command
|
||||
from setuptools import setup, find_packages, Command, Extension
|
||||
from setuptools.command.build_ext import build_ext as _build_ext
|
||||
from distutils import log
|
||||
from distutils.util import convert_path
|
||||
import subprocess as sp
|
||||
@ -23,10 +24,50 @@ def doraise_py_compile(file, cfile=None, dfile=None, doraise=False):
|
||||
|
||||
py_compile.compile = doraise_py_compile
|
||||
|
||||
needs_wheel = {'bdist_wheel'}.intersection(sys.argv)
|
||||
wheel = ['wheel'] if needs_wheel else []
|
||||
needs_bumpversion = {'release'}.intersection(sys.argv)
|
||||
bumpversion = ['bump2version'] if needs_bumpversion else []
|
||||
setup_requires = []
|
||||
|
||||
if {'bdist_wheel'}.intersection(sys.argv):
|
||||
setup_requires.append('wheel')
|
||||
|
||||
if {'release'}.intersection(sys.argv):
|
||||
setup_requires.append('bump2version')
|
||||
|
||||
try:
|
||||
__import__("cython")
|
||||
except ImportError:
|
||||
has_cython = False
|
||||
else:
|
||||
has_cython = True
|
||||
|
||||
env_with_cython = os.environ.get("FONTTOOLS_WITH_CYTHON")
|
||||
with_cython = (
|
||||
True if env_with_cython in {"1", "true", "yes"}
|
||||
else False if env_with_cython in {"0", "false", "no"}
|
||||
else None
|
||||
)
|
||||
# --with-cython/--without-cython options override environment variables
|
||||
opt_with_cython = {'--with-cython'}.intersection(sys.argv)
|
||||
opt_without_cython = {'--without-cython'}.intersection(sys.argv)
|
||||
if opt_with_cython and opt_without_cython:
|
||||
sys.exit(
|
||||
"error: the options '--with-cython' and '--without-cython' are "
|
||||
"mutually exclusive"
|
||||
)
|
||||
elif opt_with_cython:
|
||||
sys.argv.remove("--with-cython")
|
||||
with_cython = True
|
||||
elif opt_without_cython:
|
||||
sys.argv.remove("--without-cython")
|
||||
with_cython = False
|
||||
|
||||
if with_cython and not has_cython:
|
||||
setup_requires.append("cython")
|
||||
|
||||
ext_modules = []
|
||||
if with_cython is True or (with_cython is None and has_cython):
|
||||
ext_modules.append(
|
||||
Extension("fontTools.cu2qu.cu2qu", ["Lib/fontTools/cu2qu/cu2qu.py"]),
|
||||
)
|
||||
|
||||
extras_require = {
|
||||
# for fontTools.ufoLib: to read/write UFO fonts
|
||||
@ -343,7 +384,53 @@ def find_data_files(manpath="share/man"):
|
||||
return data_files
|
||||
|
||||
|
||||
setup(
|
||||
class cython_build_ext(_build_ext):
|
||||
"""Compile *.pyx source files to *.c using cythonize if Cython is
|
||||
installed and there is a working C compiler, else fall back to pure python dist.
|
||||
"""
|
||||
|
||||
def finalize_options(self):
|
||||
from Cython.Build import cythonize
|
||||
|
||||
# optionally enable line tracing for test coverage support
|
||||
linetrace = os.environ.get("CYTHON_TRACE") == "1"
|
||||
|
||||
self.distribution.ext_modules[:] = cythonize(
|
||||
self.distribution.ext_modules,
|
||||
force=linetrace or self.force,
|
||||
annotate=os.environ.get("CYTHON_ANNOTATE") == "1",
|
||||
quiet=not self.verbose,
|
||||
compiler_directives={
|
||||
"linetrace": linetrace,
|
||||
"language_level": 3,
|
||||
"embedsignature": True,
|
||||
},
|
||||
)
|
||||
|
||||
_build_ext.finalize_options(self)
|
||||
|
||||
def build_extensions(self):
|
||||
try:
|
||||
_build_ext.build_extensions(self)
|
||||
except Exception as e:
|
||||
if with_cython:
|
||||
raise
|
||||
from distutils.errors import DistutilsModuleError
|
||||
|
||||
# optional compilation failed: we delete 'ext_modules' and make sure
|
||||
# the generated wheel is 'pure'
|
||||
del self.distribution.ext_modules[:]
|
||||
try:
|
||||
bdist_wheel = self.get_finalized_command("bdist_wheel")
|
||||
except DistutilsModuleError:
|
||||
# 'bdist_wheel' command not available as wheel is not installed
|
||||
pass
|
||||
else:
|
||||
bdist_wheel.root_is_pure = True
|
||||
log.error('error: building extensions failed: %s' % e)
|
||||
|
||||
|
||||
setup_params = dict(
|
||||
name="fonttools",
|
||||
version="4.6.1.dev0",
|
||||
description="Tools to manipulate font files",
|
||||
@ -360,7 +447,8 @@ setup(
|
||||
packages=find_packages("Lib"),
|
||||
include_package_data=True,
|
||||
data_files=find_data_files(),
|
||||
setup_requires=wheel + bumpversion,
|
||||
ext_modules=ext_modules,
|
||||
setup_requires=setup_requires,
|
||||
extras_require=extras_require,
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
@ -372,6 +460,11 @@ setup(
|
||||
},
|
||||
cmdclass={
|
||||
"release": release,
|
||||
"build_ext": cython_build_ext,
|
||||
},
|
||||
**classifiers
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup(**setup_params)
|
||||
|
Loading…
x
Reference in New Issue
Block a user