merge latest cython-devel into cpp branch
[cython.git] / setup.py
1 from distutils.core import setup, Extension
2 from distutils.sysconfig import get_python_lib
3 import os, os.path
4 import sys
5
6 if 'sdist' in sys.argv and sys.platform != "win32":
7     # Record the current revision in .hgrev
8     import subprocess # os.popen is cleaner but depricated
9     changset = subprocess.Popen("hg log --rev tip | grep changeset", 
10                                 shell=True,
11                                 stdout=subprocess.PIPE).stdout.read()
12     rev = changset.decode('ISO-8859-1').split(':')[-1].strip()
13     hgrev = open('.hgrev', 'w')
14     hgrev.write(rev)
15     hgrev.close()
16
17 compiler_dir = os.path.join(get_python_lib(prefix=''), 'Cython/Compiler')
18 if sys.platform == "win32":
19     compiler_dir = compiler_dir[len(sys.prefix)+1:]
20
21 if sys.platform == "darwin":
22     # Don't create resource files on OS X tar.
23     os.environ['COPY_EXTENDED_ATTRIBUTES_DISABLE'] = 'true'
24     os.environ['COPYFILE_DISABLE'] = 'true'
25
26 setup_args = {}
27
28 def add_command_class(name, cls):
29     cmdclasses = setup_args.get('cmdclass', {})
30     cmdclasses[name] = cls
31     setup_args['cmdclass'] = cmdclasses
32
33 if sys.version_info[0] >= 3:
34     import lib2to3.refactor
35     from distutils.command.build_py \
36          import build_py_2to3 as build_py
37     # need to convert sources to Py3 on installation
38     fixers = [ fix for fix in lib2to3.refactor.get_fixers_from_package("lib2to3.fixes")
39                if fix.split('fix_')[-1] not in ('next',)
40                ]
41     build_py.fixer_names = fixers
42     add_command_class("build_py", build_py)
43
44
45 if sys.version_info < (2,4):
46     import glob
47     cython_dir = os.path.join(get_python_lib(prefix=''), 'Cython')
48     compiler_dir = os.path.join(cython_dir, 'Compiler')
49     setup_args['data_files'] = [
50         (cython_dir, [ f for pattern in
51                        ['Cython/Includes/*.pxd',
52                         'Cython/Plex/*.pxd',
53                         'Cython/Compiler/*.pxd',
54                         'Cython/Runtime/*.pyx']
55                        for f in glob.glob(pattern) ])]
56 else:
57     setup_args['package_data'] = {'Cython' : ['Includes/*.pxd',
58                                               'Plex/*.pxd',
59                                               'Compiler/*.pxd',
60                                               'Runtime/*.pyx']}
61
62 # This dict is used for passing extra arguments that are setuptools 
63 # specific to setup
64 setuptools_extra_args = {}
65
66 if 'setuptools' in sys.modules:
67     setuptools_extra_args['zip_safe'] = False
68     setuptools_extra_args['entry_points'] = {
69         'console_scripts': [
70             'cython = Cython.Compiler.Main:setuptools_main',
71         ]
72     }
73     scripts = []
74 else:
75     if os.name == "posix":
76         scripts = ["bin/cython"]
77     else:
78         scripts = ["cython.py"]
79
80 def compile_cython_modules():
81     source_root = os.path.abspath(os.path.dirname(__file__))
82     compiled_modules = ["Cython.Plex.Scanners",
83                         "Cython.Compiler.Scanning",
84                         "Cython.Compiler.Parsing",
85                         "Cython.Compiler.Visitor",
86                         "Cython.Runtime.refnanny"]
87     extensions = []
88
89     if sys.version_info[0] >= 3:
90         from Cython.Distutils import build_ext as build_ext_orig
91         for module in compiled_modules:
92             source_file = os.path.join(source_root, *module.split('.'))
93             if os.path.exists(source_file + ".py"):
94                 pyx_source_file = source_file + ".py"
95             else:
96                 pyx_source_file = source_file + ".pyx"
97             extensions.append(
98                 Extension(module, sources = [pyx_source_file])
99                 )
100
101         class build_ext(build_ext_orig):
102             def build_extensions(self):
103                 # add path where 2to3 installed the transformed sources
104                 # and make sure Python (re-)imports them from there
105                 already_imported = [ module for module in sys.modules
106                                      if module == 'Cython' or module.startswith('Cython.') ]
107                 for module in already_imported:
108                     del sys.modules[module]
109                 sys.path.insert(0, os.path.join(source_root, self.build_lib))
110
111                 build_ext_orig.build_extensions(self)
112
113         setup_args['ext_modules'] = extensions
114         add_command_class("build_ext", build_ext)
115
116     else: # Python 2.x
117         from distutils.command.build_ext import build_ext as build_ext_orig
118         try:
119             class build_ext(build_ext_orig):
120                 def build_extension(self, ext, *args, **kargs):
121                     try:
122                         build_ext_orig.build_extension(self, ext, *args, **kargs)
123                     except StandardError:
124                         print("Compilation of '%s' failed" % ext.sources[0])
125             from Cython.Compiler.Main import compile
126             from Cython import Utils
127             source_root = os.path.dirname(__file__)
128             for module in compiled_modules:
129                 source_file = os.path.join(source_root, *module.split('.'))
130                 if os.path.exists(source_file + ".py"):
131                     pyx_source_file = source_file + ".py"
132                 else:
133                     pyx_source_file = source_file + ".pyx"
134                 c_source_file = source_file + ".c"
135                 if not os.path.exists(c_source_file) or \
136                    Utils.file_newer_than(pyx_source_file,
137                                          Utils.modification_time(c_source_file)):
138                     print("Compiling module %s ..." % module)
139                     result = compile(pyx_source_file)
140                     c_source_file = result.c_file
141                 if c_source_file:
142                     extensions.append(
143                         Extension(module, sources = [c_source_file])
144                         )
145                 else:
146                     print("Compilation failed")
147             if extensions:
148                 setup_args['ext_modules'] = extensions
149                 add_command_class("build_ext", build_ext)
150         except Exception:
151             print("ERROR: %s" % sys.exc_info()[1])
152             print("Extension module compilation failed, using plain Python implementation")
153
154 try:
155     sys.argv.remove("--no-cython-compile")
156 except ValueError:
157     compile_cython_modules()
158
159 setup_args.update(setuptools_extra_args)
160
161 from Cython.Compiler.Version import version
162
163 setup(
164   name = 'Cython',
165   version = version,
166   url = 'http://www.cython.org',
167   author = 'Greg Ewing, Robert Bradshaw, Stefan Behnel, Dag Seljebotn, et al.',
168   author_email = 'cython-dev@codespeak.net',
169   description = "The Cython compiler for writing C extensions for the Python language.",
170   long_description = """\
171   The Cython language makes writing C extensions for the Python language as
172   easy as Python itself.  Cython is a source code translator based on the
173   well-known Pyrex_, but supports more cutting edge functionality and
174   optimizations.
175
176   The Cython language is very close to the Python language (and most Python
177   code is also valid Cython code), but Cython additionally supports calling C
178   functions and declaring C types on variables and class attributes. This
179   allows the compiler to generate very efficient C code from Cython code.
180
181   This makes Cython the ideal language for writing glue code for external C
182   libraries, and for fast C modules that speed up the execution of Python
183   code.
184
185   .. _Pyrex: http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
186   """,
187   classifiers = [
188     "Development Status :: 5 - Production/Stable",
189     "Intended Audience :: Developers",
190     "License :: OSI Approved :: Apache Software License",
191     "Operating System :: OS Independent",
192     "Programming Language :: Python",
193     "Programming Language :: Python :: 2",
194     "Programming Language :: Python :: 3",
195     "Programming Language :: C",
196     "Programming Language :: Cython",
197     "Topic :: Software Development :: Code Generators",
198     "Topic :: Software Development :: Compilers",
199     "Topic :: Software Development :: Libraries :: Python Modules"
200   ],
201
202   scripts = scripts,
203   packages=[
204     'Cython',
205     'Cython.Compiler',
206     'Cython.Runtime',
207     'Cython.Distutils',
208     'Cython.Plex',
209
210     'Cython.Tests',
211     'Cython.Compiler.Tests',
212     ],
213
214   # pyximport
215   py_modules = ["pyximport/__init__",
216                 "pyximport/pyximport",
217                 "pyximport/pyxbuild",
218
219                 "cython"],
220
221   **setup_args
222   )