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