setup.py 10.4 KB
Newer Older
1
#!/usr/bin/env python
2 3 4 5
try:
    from setuptools import setup, Extension
except ImportError:
    from distutils.core import setup, Extension
6
import os
7
import stat
8
import subprocess
9
import textwrap
Robert Bradshaw's avatar
Robert Bradshaw committed
10
import sys
William Stein's avatar
William Stein committed
11

12 13
import platform
is_cpython = platform.python_implementation() == 'CPython'
14

15 16
# this specifies which versions of python we support, pip >= 9 knows to skip
# versions of packages which are not compatible with the running python
17
PYTHON_REQUIRES = '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
18

19 20 21 22 23
if sys.platform == "darwin":
    # Don't create resource files on OS X tar.
    os.environ['COPY_EXTENDED_ATTRIBUTES_DISABLE'] = 'true'
    os.environ['COPYFILE_DISABLE'] = 'true'

24 25
setup_args = {}

26 27 28 29 30
def add_command_class(name, cls):
    cmdclasses = setup_args.get('cmdclass', {})
    cmdclasses[name] = cls
    setup_args['cmdclass'] = cmdclasses

31 32 33
from distutils.command.sdist import sdist as sdist_orig
class sdist(sdist_orig):
    def run(self):
34
        self.force_manifest = 1
35
        if (sys.platform != "win32" and
36
            os.path.isdir('.git')):
37
            assert os.system("git rev-parse --verify HEAD > .gitrev") == 0
38 39 40
        sdist_orig.run(self)
add_command_class('sdist', sdist)

41
pxd_include_dirs = [
42 43
    directory for directory, dirs, files
    in os.walk(os.path.join('Cython', 'Includes'))
44
    if '__init__.pyx' in files or '__init__.pxd' in files
45
    or directory == os.path.join('Cython', 'Includes')]
46 47 48 49

pxd_include_patterns = [
    p+'/*.pxd' for p in pxd_include_dirs ] + [
    p+'/*.pyx' for p in pxd_include_dirs ]
50

51 52 53 54 55 56
setup_args['package_data'] = {
    'Cython.Plex'     : ['*.pxd'],
    'Cython.Compiler' : ['*.pxd'],
    'Cython.Runtime'  : ['*.pyx', '*.pxd'],
    'Cython.Utility'  : ['*.pyx', '*.pxd', '*.c', '*.h', '*.cpp'],
    'Cython'          : [ p[7:] for p in pxd_include_patterns ],
57 58
    'Cython.Debugger.Tests': ['codefile', 'cfuncs.c'],
}
William Stein's avatar
William Stein committed
59

60
# This dict is used for passing extra arguments that are setuptools
61 62 63 64
# specific to setup
setuptools_extra_args = {}

if 'setuptools' in sys.modules:
65
    setuptools_extra_args['python_requires'] = PYTHON_REQUIRES
66 67 68 69
    setuptools_extra_args['zip_safe'] = False
    setuptools_extra_args['entry_points'] = {
        'console_scripts': [
            'cython = Cython.Compiler.Main:setuptools_main',
Robert Bradshaw's avatar
Robert Bradshaw committed
70 71
            'cythonize = Cython.Build.Cythonize:main',
            'cygdb = Cython.Debugger.Cygdb:main',
72 73 74
        ]
    }
    scripts = []
William Stein's avatar
William Stein committed
75
else:
76
    if os.name == "posix":
Robert Bradshaw's avatar
Robert Bradshaw committed
77
        scripts = ["bin/cython", "bin/cythonize", "bin/cygdb"]
78
    else:
Robert Bradshaw's avatar
Robert Bradshaw committed
79
        scripts = ["cython.py", "cythonize.py", "cygdb.py"]
80

81

82
def compile_cython_modules(profile=False, compile_more=False, cython_with_refnanny=False):
83
    source_root = os.path.abspath(os.path.dirname(__file__))
Stefan Behnel's avatar
Stefan Behnel committed
84 85 86
    compiled_modules = [
        "Cython.Plex.Scanners",
        "Cython.Plex.Actions",
87
        "Cython.Plex.Machines",
88
        "Cython.Plex.Transitions",
89
        "Cython.Plex.DFA",
Stefan Behnel's avatar
Stefan Behnel committed
90 91 92 93
        "Cython.Compiler.Scanning",
        "Cython.Compiler.Visitor",
        "Cython.Compiler.FlowControl",
        "Cython.Runtime.refnanny",
94
        "Cython.Compiler.FusedNode",
Stefan Behnel's avatar
Stefan Behnel committed
95 96
        "Cython.Tempita._tempita",
    ]
97 98
    if compile_more:
        compiled_modules.extend([
99 100 101
            "Cython.StringIOTree",
            "Cython.Compiler.Code",
            "Cython.Compiler.Lexicon",
102
            "Cython.Compiler.Parsing",
103
            "Cython.Compiler.Pythran",
104
            "Cython.Build.Dependencies",
105 106 107 108 109 110
            "Cython.Compiler.ParseTreeTransforms",
            "Cython.Compiler.Nodes",
            "Cython.Compiler.ExprNodes",
            "Cython.Compiler.ModuleNode",
            "Cython.Compiler.Optimize",
            ])
William Stein's avatar
William Stein committed
111

112 113 114 115 116
    from distutils.spawn import find_executable
    from distutils.sysconfig import get_python_inc
    pgen = find_executable(
        'pgen', os.pathsep.join([os.environ['PATH'], os.path.join(get_python_inc(), '..', 'Parser')]))
    if not pgen:
117
        sys.stderr.write("Unable to find pgen, not compiling formal grammar.\n")
118 119
    else:
        parser_dir = os.path.join(os.path.dirname(__file__), 'Cython', 'Parser')
120
        grammar = os.path.join(parser_dir, 'Grammar')
121 122
        subprocess.check_call([
            pgen,
123
            os.path.join(grammar),
124 125 126
            os.path.join(parser_dir, 'graminit.h'),
            os.path.join(parser_dir, 'graminit.c'),
            ])
127 128 129 130
        cst_pyx = os.path.join(parser_dir, 'ConcreteSyntaxTree.pyx')
        if os.stat(grammar)[stat.ST_MTIME] > os.stat(cst_pyx)[stat.ST_MTIME]:
            mtime = os.stat(grammar)[stat.ST_MTIME]
            os.utime(cst_pyx, (mtime, mtime))
131 132 133 134
        compiled_modules.extend([
                "Cython.Parser.ConcreteSyntaxTree",
            ])

135 136 137
    defines = []
    if cython_with_refnanny:
        defines.append(('CYTHON_REFNANNY', '1'))
William Stein's avatar
William Stein committed
138

139
    extensions = []
140 141 142 143 144 145 146 147 148 149 150 151 152
    for module in compiled_modules:
        source_file = os.path.join(source_root, *module.split('.'))
        if os.path.exists(source_file + ".py"):
            pyx_source_file = source_file + ".py"
        else:
            pyx_source_file = source_file + ".pyx"
        dep_files = []
        if os.path.exists(source_file + '.pxd'):
            dep_files.append(source_file + '.pxd')
        if '.refnanny' in module:
            defines_for_module = []
        else:
            defines_for_module = defines
153 154 155 156 157
        extensions.append(Extension(
            module, sources=[pyx_source_file],
            define_macros=defines_for_module,
            depends=dep_files))
        # XXX hack around setuptools quirk for '*.pyx' sources
158 159
        extensions[-1].sources[0] = pyx_source_file

160
    from Cython.Distutils.build_ext import new_build_ext
161
    from Cython.Compiler.Options import get_directive_defaults
162 163 164 165 166 167
    get_directive_defaults().update(
        language_level=2,
        binding=False,
        always_allow_keywords=False,
        autotestdict=False,
    )
168 169 170
    if profile:
        get_directive_defaults()['profile'] = True
        sys.stderr.write("Enabled profiling for the Cython binary modules\n")
171

172 173
    # not using cythonize() directly to let distutils decide whether building extensions was requested
    add_command_class("build_ext", new_build_ext)
174 175 176
    setup_args['ext_modules'] = extensions


Stefan Behnel's avatar
Stefan Behnel committed
177 178 179 180
cython_profile = '--cython-profile' in sys.argv
if cython_profile:
    sys.argv.remove('--cython-profile')

181 182 183 184 185 186
try:
    sys.argv.remove("--cython-compile-all")
    cython_compile_more = True
except ValueError:
    cython_compile_more = False

187 188 189 190 191 192
try:
    sys.argv.remove("--cython-with-refnanny")
    cython_with_refnanny = True
except ValueError:
    cython_with_refnanny = False

193 194
try:
    sys.argv.remove("--no-cython-compile")
195
    compile_cython_itself = False
196
except ValueError:
197 198
    compile_cython_itself = True

199
setup_args.update(setuptools_extra_args)
200

201

202
def dev_status(version):
203 204 205 206 207 208 209 210 211 212
    if 'b' in version or 'c' in version:
        # 1b1, 1beta1, 2rc1, ...
        return 'Development Status :: 4 - Beta'
    elif 'a' in version:
        # 1a1, 1alpha1, ...
        return 'Development Status :: 3 - Alpha'
    else:
        return 'Development Status :: 5 - Production/Stable'


213 214 215 216 217 218
packages = [
    'Cython',
    'Cython.Build',
    'Cython.Compiler',
    'Cython.Runtime',
    'Cython.Distutils',
219 220
    'Cython.Debugger',
    'Cython.Debugger.Tests',
221 222
    'Cython.Plex',
    'Cython.Tests',
223
    'Cython.Build.Tests',
224
    'Cython.Compiler.Tests',
225
    'Cython.Utility',
Mark Florisson's avatar
Mark Florisson committed
226
    'Cython.Tempita',
227
    'pyximport',
228 229
]

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246

def run_build():
    if compile_cython_itself and (is_cpython or cython_compile_more):
        compile_cython_modules(cython_profile, cython_compile_more, cython_with_refnanny)

    from Cython import __version__ as version
    setup(
        name='Cython',
        version=version,
        url='https://cython.org/',
        author='Robert Bradshaw, Stefan Behnel, Dag Seljebotn, Greg Ewing, et al.',
        author_email='cython-devel@python.org',
        description="The Cython compiler for writing C extensions for the Python language.",
        long_description=textwrap.dedent("""\
        The Cython language makes writing C extensions for the Python language as
        easy as Python itself.  Cython is a source code translator based on Pyrex_,
        but supports more cutting edge functionality and optimizations.
247

248 249 250 251 252
        The Cython language is a superset of the Python language (almost all Python
        code is also valid Cython code), but Cython additionally supports optional
        static typing to natively call C functions, operate with C++ classes and
        declare fast C types on variables and class attributes.  This allows the
        compiler to generate very efficient C code from Cython code.
253

254 255 256
        This makes Cython the ideal language for writing glue code for external
        C/C++ libraries, and for fast C modules that speed up the execution of
        Python code.
257

258 259 260 261
        Note that for one-time builds, e.g. for CI/testing, on platforms that are not
        covered by one of the wheel packages provided on PyPI *and* the pure Python wheel
        that we provide is not used, it is substantially faster than a full source build
        to install an uncompiled (slower) version of Cython with::
262

263
            pip install Cython --install-option="--no-cython-compile"
264

265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
        .. _Pyrex: https://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
        """),
        license='Apache',
        classifiers=[
            dev_status(version),
            "Intended Audience :: Developers",
            "License :: OSI Approved :: Apache Software License",
            "Operating System :: OS Independent",
            "Programming Language :: Python",
            "Programming Language :: Python :: 2",
            "Programming Language :: Python :: 2.7",
            "Programming Language :: Python :: 3",
            "Programming Language :: Python :: 3.4",
            "Programming Language :: Python :: 3.5",
            "Programming Language :: Python :: 3.6",
            "Programming Language :: Python :: 3.7",
            "Programming Language :: Python :: 3.8",
            "Programming Language :: Python :: Implementation :: CPython",
            "Programming Language :: Python :: Implementation :: PyPy",
            "Programming Language :: C",
            "Programming Language :: Cython",
            "Topic :: Software Development :: Code Generators",
            "Topic :: Software Development :: Compilers",
            "Topic :: Software Development :: Libraries :: Python Modules"
        ],

        scripts=scripts,
        packages=packages,
        py_modules=["cython"],
        **setup_args
    )


if __name__ == '__main__':
    run_build()