setup.py 10.9 KB
Newer Older
1
from distutils.core import setup, Extension
William Stein's avatar
William Stein committed
2
from distutils.sysconfig import get_python_lib
3
import os, os.path
Robert Bradshaw's avatar
Robert Bradshaw committed
4
import sys
William Stein's avatar
William Stein committed
5

Stefan Behnel's avatar
Stefan Behnel committed
6
if 'sdist' in sys.argv and sys.platform != "win32" and sys.version_info >= (2,4):
7
    # Record the current revision in .hgrev
Stefan Behnel's avatar
Stefan Behnel committed
8
    import subprocess # os.popen is cleaner but deprecated
9 10 11
    changeset = subprocess.Popen("hg identify --id --rev tip".split(),
                                 stdout=subprocess.PIPE).stdout.read()
    rev = changeset.decode('ISO-8859-1').strip()
12 13 14 15
    hgrev = open('.hgrev', 'w')
    hgrev.write(rev)
    hgrev.close()

16 17 18 19 20
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'

21 22
setup_args = {}

23 24 25 26 27
def add_command_class(name, cls):
    cmdclasses = setup_args.get('cmdclass', {})
    cmdclasses[name] = cls
    setup_args['cmdclass'] = cmdclasses

28 29 30 31 32 33 34 35 36
if sys.version_info[0] >= 3:
    import lib2to3.refactor
    from distutils.command.build_py \
         import build_py_2to3 as build_py
    # need to convert sources to Py3 on installation
    fixers = [ fix for fix in lib2to3.refactor.get_fixers_from_package("lib2to3.fixes")
               if fix.split('fix_')[-1] not in ('next',)
               ]
    build_py.fixer_names = fixers
37
    add_command_class("build_py", build_py)
38

39 40 41
pxd_include_dirs = [
    directory for directory, dirs, files in os.walk('Cython/Includes')
    if '__init__.pyx' in files or '__init__.pxd' in files
42
    or directory == 'Cython/Includes' or directory == 'Cython/Includes/Deprecated']
43 44 45 46

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

48
if sys.version_info < (2,4):
Stefan Behnel's avatar
Stefan Behnel committed
49
    install_base_dir = get_python_lib(prefix='')
50
    import glob
51 52 53 54 55
    patterns = pxd_include_patterns + [
        'Cython/Plex/*.pxd',
        'Cython/Compiler/*.pxd',
        'Cython/Runtime/*.pyx'
        ]
56
    setup_args['data_files'] = [
Stefan Behnel's avatar
Stefan Behnel committed
57 58
        (os.path.dirname(os.path.join(install_base_dir, pattern)),
         [ f for f in glob.glob(pattern) ])
59
        for pattern in patterns
Stefan Behnel's avatar
Stefan Behnel committed
60
        ]
61
else:
62 63 64 65 66 67
    setup_args['package_data'] = {
        'Cython.Plex'     : ['*.pxd'],
        'Cython.Compiler' : ['*.pxd'],
        'Cython.Runtime'  : ['*.pyx', '*.pxd'],
        'Cython'          : [ p[7:] for p in pxd_include_patterns ],
        }
William Stein's avatar
William Stein committed
68

69 70 71 72 73 74 75 76 77 78 79 80
# This dict is used for passing extra arguments that are setuptools 
# specific to setup
setuptools_extra_args = {}

if 'setuptools' in sys.modules:
    setuptools_extra_args['zip_safe'] = False
    setuptools_extra_args['entry_points'] = {
        'console_scripts': [
            'cython = Cython.Compiler.Main:setuptools_main',
        ]
    }
    scripts = []
William Stein's avatar
William Stein committed
81
else:
82 83 84 85 86
    if os.name == "posix":
        scripts = ["bin/cython"]
    else:
        scripts = ["cython.py"]

87
def compile_cython_modules(profile=False, compile_more=False):
88 89
    source_root = os.path.abspath(os.path.dirname(__file__))
    compiled_modules = ["Cython.Plex.Scanners",
90
                        "Cython.Plex.Actions",
91 92 93 94
                        "Cython.Compiler.Scanning",
                        "Cython.Compiler.Parsing",
                        "Cython.Compiler.Visitor",
                        "Cython.Runtime.refnanny"]
95 96 97 98 99 100 101 102
    if compile_more:
        compiled_modules.extend([
            "Cython.Compiler.ParseTreeTransforms",
            "Cython.Compiler.Nodes",
            "Cython.Compiler.ExprNodes",
            "Cython.Compiler.ModuleNode",
            "Cython.Compiler.Optimize",
            ])
William Stein's avatar
William Stein committed
103

104
    extensions = []
105
    if sys.version_info[0] >= 3:
106
        from Cython.Distutils import build_ext as build_ext_orig
107 108
        for module in compiled_modules:
            source_file = os.path.join(source_root, *module.split('.'))
109
            if os.path.exists(source_file + ".py"):
110
                pyx_source_file = source_file + ".py"
111
            else:
112
                pyx_source_file = source_file + ".pyx"
113 114 115
            dep_files = []
            if os.path.exists(source_file + '.pxd'):
                dep_files.append(source_file + '.pxd')
116
            extensions.append(
117 118
                Extension(module, sources = [pyx_source_file],
                          depends = dep_files)
119 120 121
                )

        class build_ext(build_ext_orig):
122 123 124 125 126
            # we must keep the original modules alive to make sure
            # their code keeps working when we remove them from
            # sys.modules
            dead_modules = []

127 128 129 130 131
            def build_extensions(self):
                # add path where 2to3 installed the transformed sources
                # and make sure Python (re-)imports them from there
                already_imported = [ module for module in sys.modules
                                     if module == 'Cython' or module.startswith('Cython.') ]
132
                keep_alive = self.dead_modules.append
133
                for module in already_imported:
134
                    keep_alive(sys.modules[module])
135 136 137
                    del sys.modules[module]
                sys.path.insert(0, os.path.join(source_root, self.build_lib))

138 139 140 141
                if profile:
                    from Cython.Compiler.Options import directive_defaults
                    directive_defaults['profile'] = True
                    print("Enabled profiling for the Cython binary modules")
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
                build_ext_orig.build_extensions(self)

        setup_args['ext_modules'] = extensions
        add_command_class("build_ext", build_ext)

    else: # Python 2.x
        from distutils.command.build_ext import build_ext as build_ext_orig
        try:
            class build_ext(build_ext_orig):
                def build_extension(self, ext, *args, **kargs):
                    try:
                        build_ext_orig.build_extension(self, ext, *args, **kargs)
                    except StandardError:
                        print("Compilation of '%s' failed" % ext.sources[0])
            from Cython.Compiler.Main import compile
            from Cython import Utils
158 159 160 161
            if profile:
                from Cython.Compiler.Options import directive_defaults
                directive_defaults['profile'] = True
                print("Enabled profiling for the Cython binary modules")
162 163 164 165 166 167 168 169
            source_root = os.path.dirname(__file__)
            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"
                c_source_file = source_file + ".c"
170 171 172 173 174 175 176 177 178 179 180 181
                source_is_newer = False
                if not os.path.exists(c_source_file):
                    source_is_newer = True
                else:
                    c_last_modified = Utils.modification_time(c_source_file)
                    if Utils.file_newer_than(pyx_source_file, c_last_modified):
                        source_is_newer = True
                    else:
                        pxd_source_file = source_file + ".pxd"
                        if os.path.exists(pxd_source_file) and Utils.file_newer_than(pxd_source_file, c_last_modified):
                            source_is_newer = True
                if source_is_newer:
182 183 184 185
                    print("Compiling module %s ..." % module)
                    result = compile(pyx_source_file)
                    c_source_file = result.c_file
                if c_source_file:
186 187 188 189 190 191
                    # Py2 distutils can't handle unicode file paths
                    if isinstance(c_source_file, unicode):
                        filename_encoding = sys.getfilesystemencoding()
                        if filename_encoding is None:
                            filename_encoding = sys.getdefaultencoding()
                        c_source_file = c_source_file.encode(filename_encoding)
192 193 194 195 196 197 198 199 200
                    extensions.append(
                        Extension(module, sources = [c_source_file])
                        )
                else:
                    print("Compilation failed")
            if extensions:
                setup_args['ext_modules'] = extensions
                add_command_class("build_ext", build_ext)
        except Exception:
201 202 203 204 205 206 207 208 209
            print('''
ERROR: %s

Extension module compilation failed, looks like Cython cannot run
properly on this system.  To work around this, pass the option
"--no-cython-compile".  This will install a pure Python version of
Cython without compiling its own sources.
''' % sys.exc_info()[1])
            raise
210

Stefan Behnel's avatar
Stefan Behnel committed
211 212 213 214
cython_profile = '--cython-profile' in sys.argv
if cython_profile:
    sys.argv.remove('--cython-profile')

215 216 217 218 219 220
try:
    sys.argv.remove("--cython-compile-all")
    cython_compile_more = True
except ValueError:
    cython_compile_more = False

221 222 223
try:
    sys.argv.remove("--no-cython-compile")
except ValueError:
224
    compile_cython_modules(cython_profile, cython_compile_more)
225

226
setup_args.update(setuptools_extra_args)
227

228
from Cython import __version__ as version
229

William Stein's avatar
William Stein committed
230
setup(
231
  name = 'Cython',
William Stein's avatar
William Stein committed
232 233
  version = version,
  url = 'http://www.cython.org',
234 235
  author = 'Greg Ewing, Robert Bradshaw, Stefan Behnel, Dag Seljebotn, et al.',
  author_email = 'cython-dev@codespeak.net',
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
  description = "The Cython compiler for writing C extensions for the Python language.",
  long_description = """\
  The Cython language makes writing C extensions for the Python language as
  easy as Python itself.  Cython is a source code translator based on the
  well-known Pyrex_, but supports more cutting edge functionality and
  optimizations.

  The Cython language is very close to the Python language (and most Python
  code is also valid Cython code), but Cython additionally supports calling C
  functions and declaring C types on variables and class attributes. This
  allows the compiler to generate very efficient C code from Cython code.

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

  .. _Pyrex: http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
  """,
  classifiers = [
    "Development Status :: 5 - Production/Stable",
    "Intended Audience :: Developers",
257
    "License :: OSI Approved :: Apache Software License",
258 259
    "Operating System :: OS Independent",
    "Programming Language :: Python",
Stefan Behnel's avatar
Stefan Behnel committed
260 261
    "Programming Language :: Python :: 2",
    "Programming Language :: Python :: 3",
Robert Bradshaw's avatar
Robert Bradshaw committed
262
    "Programming Language :: C",
263
    "Programming Language :: Cython",
264 265 266 267 268
    "Topic :: Software Development :: Code Generators",
    "Topic :: Software Development :: Compilers",
    "Topic :: Software Development :: Libraries :: Python Modules"
  ],

William Stein's avatar
William Stein committed
269 270 271
  scripts = scripts,
  packages=[
    'Cython',
Robert Bradshaw's avatar
Robert Bradshaw committed
272
    'Cython.Build',
William Stein's avatar
William Stein committed
273
    'Cython.Compiler',
274
    'Cython.Runtime',
William Stein's avatar
William Stein committed
275
    'Cython.Distutils',
Robert Bradshaw's avatar
Robert Bradshaw committed
276 277 278 279
    'Cython.Plex',

    'Cython.Tests',
    'Cython.Compiler.Tests',
William Stein's avatar
William Stein committed
280
    ],
281

282
  # pyximport
283 284
  py_modules = ["pyximport/__init__",
                "pyximport/pyximport",
285 286
                "pyximport/pyxbuild",

287
                "cython"],
288

289
  **setup_args
William Stein's avatar
William Stein committed
290
  )