1#!/usr/bin/env python
2try:
3    from setuptools import setup, Extension
4except ImportError:
5    from distutils.core import setup, Extension
6import os
7import stat
8import subprocess
9import textwrap
10import sys
11
12import platform
13is_cpython = platform.python_implementation() == 'CPython'
14
15# this specifies which versions of python we support, pip >= 9 knows to skip
16# versions of packages which are not compatible with the running python
17PYTHON_REQUIRES = '>=2.6, !=3.0.*, !=3.1.*, !=3.2.*'
18
19if sys.platform == "darwin":
20    # Don't create resource files on OS X tar.
21    os.environ['COPY_EXTENDED_ATTRIBUTES_DISABLE'] = 'true'
22    os.environ['COPYFILE_DISABLE'] = 'true'
23
24setup_args = {}
25
26def add_command_class(name, cls):
27    cmdclasses = setup_args.get('cmdclass', {})
28    cmdclasses[name] = cls
29    setup_args['cmdclass'] = cmdclasses
30
31from distutils.command.sdist import sdist as sdist_orig
32class sdist(sdist_orig):
33    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        sdist_orig.run(self)
39add_command_class('sdist', sdist)
40
41pxd_include_dirs = [
42    directory for directory, dirs, files
43    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    or directory == os.path.join('Cython', 'Includes', 'Deprecated')]
47
48pxd_include_patterns = [
49    p+'/*.pxd' for p in pxd_include_dirs ] + [
50    p+'/*.pyx' for p in pxd_include_dirs ]
51
52setup_args['package_data'] = {
53    'Cython.Plex'     : ['*.pxd'],
54    'Cython.Compiler' : ['*.pxd'],
55    'Cython.Runtime'  : ['*.pyx', '*.pxd'],
56    'Cython.Utility'  : ['*.pyx', '*.pxd', '*.c', '*.h', '*.cpp'],
57    'Cython'          : [ p[7:] for p in pxd_include_patterns ],
58    'Cython.Debugger.Tests': ['codefile', 'cfuncs.c'],
59}
60
61# This dict is used for passing extra arguments that are setuptools
62# specific to setup
63setuptools_extra_args = {}
64
65if 'setuptools' in sys.modules:
66    setuptools_extra_args['python_requires'] = PYTHON_REQUIRES
67    setuptools_extra_args['zip_safe'] = False
68    setuptools_extra_args['entry_points'] = {
69        'console_scripts': [
70            'cython = Cython.Compiler.Main:setuptools_main',
71            'cythonize = Cython.Build.Cythonize:main',
72            'cygdb = Cython.Debugger.Cygdb:main',
73        ]
74    }
75    scripts = []
76else:
77    if os.name == "posix":
78        scripts = ["bin/cython", "bin/cythonize", "bin/cygdb"]
79    else:
80        scripts = ["cython.py", "cythonize.py", "cygdb.py"]
81
82
83def compile_cython_modules(profile=False, compile_more=False, cython_with_refnanny=False):
84    source_root = os.path.abspath(os.path.dirname(__file__))
85    compiled_modules = [
86        "Cython.Plex.Scanners",
87        "Cython.Plex.Actions",
88        "Cython.Compiler.Scanning",
89        "Cython.Compiler.Visitor",
90        "Cython.Compiler.FlowControl",
91        "Cython.Runtime.refnanny",
92        "Cython.Compiler.FusedNode",
93        "Cython.Tempita._tempita",
94    ]
95    if compile_more:
96        compiled_modules.extend([
97            "Cython.StringIOTree",
98            "Cython.Compiler.Code",
99            "Cython.Compiler.Lexicon",
100            "Cython.Compiler.Parsing",
101            "Cython.Compiler.Pythran",
102            "Cython.Build.Dependencies",
103            "Cython.Compiler.ParseTreeTransforms",
104            "Cython.Compiler.Nodes",
105            "Cython.Compiler.ExprNodes",
106            "Cython.Compiler.ModuleNode",
107            "Cython.Compiler.Optimize",
108            ])
109
110    from distutils.spawn import find_executable
111    from distutils.sysconfig import get_python_inc
112    pgen = find_executable(
113        'pgen', os.pathsep.join([os.environ['PATH'], os.path.join(get_python_inc(), '..', 'Parser')]))
114    if not pgen:
115        sys.stderr.write("Unable to find pgen, not compiling formal grammar.\n")
116    else:
117        parser_dir = os.path.join(os.path.dirname(__file__), 'Cython', 'Parser')
118        grammar = os.path.join(parser_dir, 'Grammar')
119        subprocess.check_call([
120            pgen,
121            os.path.join(grammar),
122            os.path.join(parser_dir, 'graminit.h'),
123            os.path.join(parser_dir, 'graminit.c'),
124            ])
125        cst_pyx = os.path.join(parser_dir, 'ConcreteSyntaxTree.pyx')
126        if os.stat(grammar)[stat.ST_MTIME] > os.stat(cst_pyx)[stat.ST_MTIME]:
127            mtime = os.stat(grammar)[stat.ST_MTIME]
128            os.utime(cst_pyx, (mtime, mtime))
129        compiled_modules.extend([
130                "Cython.Parser.ConcreteSyntaxTree",
131            ])
132
133    defines = []
134    if cython_with_refnanny:
135        defines.append(('CYTHON_REFNANNY', '1'))
136
137    extensions = []
138    for module in compiled_modules:
139        source_file = os.path.join(source_root, *module.split('.'))
140        if os.path.exists(source_file + ".py"):
141            pyx_source_file = source_file + ".py"
142        else:
143            pyx_source_file = source_file + ".pyx"
144        dep_files = []
145        if os.path.exists(source_file + '.pxd'):
146            dep_files.append(source_file + '.pxd')
147        if '.refnanny' in module:
148            defines_for_module = []
149        else:
150            defines_for_module = defines
151        extensions.append(Extension(
152            module, sources=[pyx_source_file],
153            define_macros=defines_for_module,
154            depends=dep_files))
155        # XXX hack around setuptools quirk for '*.pyx' sources
156        extensions[-1].sources[0] = pyx_source_file
157
158    from Cython.Distutils.build_ext import new_build_ext
159    from Cython.Compiler.Options import get_directive_defaults
160    get_directive_defaults()['language_level'] = 2
161    if profile:
162        get_directive_defaults()['profile'] = True
163        sys.stderr.write("Enabled profiling for the Cython binary modules\n")
164
165    # not using cythonize() directly to let distutils decide whether building extensions was requested
166    add_command_class("build_ext", new_build_ext)
167    setup_args['ext_modules'] = extensions
168
169
170cython_profile = '--cython-profile' in sys.argv
171if cython_profile:
172    sys.argv.remove('--cython-profile')
173
174try:
175    sys.argv.remove("--cython-compile-all")
176    cython_compile_more = True
177except ValueError:
178    cython_compile_more = False
179
180try:
181    sys.argv.remove("--cython-with-refnanny")
182    cython_with_refnanny = True
183except ValueError:
184    cython_with_refnanny = False
185
186try:
187    sys.argv.remove("--no-cython-compile")
188    compile_cython_itself = False
189except ValueError:
190    compile_cython_itself = True
191
192if compile_cython_itself and (is_cpython or cython_compile_more):
193    compile_cython_modules(cython_profile, cython_compile_more, cython_with_refnanny)
194
195setup_args.update(setuptools_extra_args)
196
197from Cython import __version__ as version
198
199
200def dev_status():
201    if 'b' in version or 'c' in version:
202        # 1b1, 1beta1, 2rc1, ...
203        return 'Development Status :: 4 - Beta'
204    elif 'a' in version:
205        # 1a1, 1alpha1, ...
206        return 'Development Status :: 3 - Alpha'
207    else:
208        return 'Development Status :: 5 - Production/Stable'
209
210
211packages = [
212    'Cython',
213    'Cython.Build',
214    'Cython.Compiler',
215    'Cython.Runtime',
216    'Cython.Distutils',
217    'Cython.Debugger',
218    'Cython.Debugger.Tests',
219    'Cython.Plex',
220    'Cython.Tests',
221    'Cython.Build.Tests',
222    'Cython.Compiler.Tests',
223    'Cython.Utility',
224    'Cython.Tempita',
225    'pyximport',
226]
227
228setup(
229    name='Cython',
230    version=version,
231    url='http://cython.org/',
232    author='Robert Bradshaw, Stefan Behnel, Dag Seljebotn, Greg Ewing, et al.',
233    author_email='cython-devel@python.org',
234    description="The Cython compiler for writing C extensions for the Python language.",
235    long_description=textwrap.dedent("""\
236    The Cython language makes writing C extensions for the Python language as
237    easy as Python itself.  Cython is a source code translator based on Pyrex_,
238    but supports more cutting edge functionality and optimizations.
239
240    The Cython language is a superset of the Python language (almost all Python
241    code is also valid Cython code), but Cython additionally supports optional
242    static typing to natively call C functions, operate with C++ classes and
243    declare fast C types on variables and class attributes.  This allows the
244    compiler to generate very efficient C code from Cython code.
245
246    This makes Cython the ideal language for writing glue code for external
247    C/C++ libraries, and for fast C modules that speed up the execution of
248    Python code.
249
250    Note that for one-time builds, e.g. for CI/testing, on platforms that are not
251    covered by one of the wheel packages provided on PyPI *and* the pure Python wheel
252    that we provide is not used, it is substantially faster than a full source build
253    to install an uncompiled (slower) version of Cython with::
254
255        pip install Cython --install-option="--no-cython-compile"
256
257    .. _Pyrex: http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
258    """),
259    license='Apache',
260    classifiers=[
261        dev_status(),
262        "Intended Audience :: Developers",
263        "License :: OSI Approved :: Apache Software License",
264        "Operating System :: OS Independent",
265        "Programming Language :: Python",
266        "Programming Language :: Python :: 2",
267        "Programming Language :: Python :: 2.6",
268        "Programming Language :: Python :: 2.7",
269        "Programming Language :: Python :: 3",
270        "Programming Language :: Python :: 3.4",
271        "Programming Language :: Python :: 3.5",
272        "Programming Language :: Python :: 3.6",
273        "Programming Language :: Python :: 3.7",
274        "Programming Language :: Python :: 3.8",
275        "Programming Language :: Python :: 3.9",
276        "Programming Language :: Python :: Implementation :: CPython",
277        "Programming Language :: Python :: Implementation :: PyPy",
278        "Programming Language :: C",
279        "Programming Language :: Cython",
280        "Topic :: Software Development :: Code Generators",
281        "Topic :: Software Development :: Compilers",
282        "Topic :: Software Development :: Libraries :: Python Modules"
283    ],
284
285    scripts=scripts,
286    packages=packages,
287    py_modules=["cython"],
288    **setup_args
289)
290