more cythonisation in the scanner/parser
[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.Plex.Actions",
91                         "Cython.Compiler.Scanning",
92                         "Cython.Compiler.Parsing",
93                         "Cython.Compiler.Visitor",
94                         "Cython.Runtime.refnanny"]
95     extensions = []
96
97     if sys.version_info[0] >= 3:
98         from Cython.Distutils import build_ext as build_ext_orig
99         for module in compiled_modules:
100             source_file = os.path.join(source_root, *module.split('.'))
101             if os.path.exists(source_file + ".py"):
102                 pyx_source_file = source_file + ".py"
103             else:
104                 pyx_source_file = source_file + ".pyx"
105             dep_files = []
106             if os.path.exists(source_file + '.pxd'):
107                 dep_files.append(source_file + '.pxd')
108             extensions.append(
109                 Extension(module, sources = [pyx_source_file],
110                           depends = dep_files)
111                 )
112
113         class build_ext(build_ext_orig):
114             # we must keep the original modules alive to make sure
115             # their code keeps working when we remove them from
116             # sys.modules
117             dead_modules = []
118
119             def build_extensions(self):
120                 # add path where 2to3 installed the transformed sources
121                 # and make sure Python (re-)imports them from there
122                 already_imported = [ module for module in sys.modules
123                                      if module == 'Cython' or module.startswith('Cython.') ]
124                 keep_alive = self.dead_modules.append
125                 for module in already_imported:
126                     keep_alive(sys.modules[module])
127                     del sys.modules[module]
128                 sys.path.insert(0, os.path.join(source_root, self.build_lib))
129
130                 if profile:
131                     from Cython.Compiler.Options import directive_defaults
132                     directive_defaults['profile'] = True
133                     print("Enabled profiling for the Cython binary modules")
134                 build_ext_orig.build_extensions(self)
135
136         setup_args['ext_modules'] = extensions
137         add_command_class("build_ext", build_ext)
138
139     else: # Python 2.x
140         from distutils.command.build_ext import build_ext as build_ext_orig
141         try:
142             class build_ext(build_ext_orig):
143                 def build_extension(self, ext, *args, **kargs):
144                     try:
145                         build_ext_orig.build_extension(self, ext, *args, **kargs)
146                     except StandardError:
147                         print("Compilation of '%s' failed" % ext.sources[0])
148             from Cython.Compiler.Main import compile
149             from Cython import Utils
150             if profile:
151                 from Cython.Compiler.Options import directive_defaults
152                 directive_defaults['profile'] = True
153                 print("Enabled profiling for the Cython binary modules")
154             source_root = os.path.dirname(__file__)
155             for module in compiled_modules:
156                 source_file = os.path.join(source_root, *module.split('.'))
157                 if os.path.exists(source_file + ".py"):
158                     pyx_source_file = source_file + ".py"
159                 else:
160                     pyx_source_file = source_file + ".pyx"
161                 c_source_file = source_file + ".c"
162                 source_is_newer = False
163                 if not os.path.exists(c_source_file):
164                     source_is_newer = True
165                 else:
166                     c_last_modified = Utils.modification_time(c_source_file)
167                     if Utils.file_newer_than(pyx_source_file, c_last_modified):
168                         source_is_newer = True
169                     else:
170                         pxd_source_file = source_file + ".pxd"
171                         if os.path.exists(pxd_source_file) and Utils.file_newer_than(pxd_source_file, c_last_modified):
172                             source_is_newer = True
173                 if source_is_newer:
174                     print("Compiling module %s ..." % module)
175                     result = compile(pyx_source_file)
176                     c_source_file = result.c_file
177                 if c_source_file:
178                     # Py2 distutils can't handle unicode file paths
179                     if isinstance(c_source_file, unicode):
180                         filename_encoding = sys.getfilesystemencoding()
181                         if filename_encoding is None:
182                             filename_encoding = sys.getdefaultencoding()
183                         c_source_file = c_source_file.encode(filename_encoding)
184                     extensions.append(
185                         Extension(module, sources = [c_source_file])
186                         )
187                 else:
188                     print("Compilation failed")
189             if extensions:
190                 setup_args['ext_modules'] = extensions
191                 add_command_class("build_ext", build_ext)
192         except Exception:
193             print('''
194 ERROR: %s
195
196 Extension module compilation failed, looks like Cython cannot run
197 properly on this system.  To work around this, pass the option
198 "--no-cython-compile".  This will install a pure Python version of
199 Cython without compiling its own sources.
200 ''' % sys.exc_info()[1])
201             raise
202
203 cython_profile = '--cython-profile' in sys.argv
204 if cython_profile:
205     sys.argv.remove('--cython-profile')
206
207 try:
208     sys.argv.remove("--no-cython-compile")
209 except ValueError:
210     compile_cython_modules(cython_profile)
211
212 setup_args.update(setuptools_extra_args)
213
214 from Cython import __version__ as version
215
216 setup(
217   name = 'Cython',
218   version = version,
219   url = 'http://www.cython.org',
220   author = 'Greg Ewing, Robert Bradshaw, Stefan Behnel, Dag Seljebotn, et al.',
221   author_email = 'cython-dev@codespeak.net',
222   description = "The Cython compiler for writing C extensions for the Python language.",
223   long_description = """\
224   The Cython language makes writing C extensions for the Python language as
225   easy as Python itself.  Cython is a source code translator based on the
226   well-known Pyrex_, but supports more cutting edge functionality and
227   optimizations.
228
229   The Cython language is very close to the Python language (and most Python
230   code is also valid Cython code), but Cython additionally supports calling C
231   functions and declaring C types on variables and class attributes. This
232   allows the compiler to generate very efficient C code from Cython code.
233
234   This makes Cython the ideal language for writing glue code for external C
235   libraries, and for fast C modules that speed up the execution of Python
236   code.
237
238   .. _Pyrex: http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
239   """,
240   classifiers = [
241     "Development Status :: 5 - Production/Stable",
242     "Intended Audience :: Developers",
243     "License :: OSI Approved :: Apache Software License",
244     "Operating System :: OS Independent",
245     "Programming Language :: Python",
246     "Programming Language :: Python :: 2",
247     "Programming Language :: Python :: 3",
248     "Programming Language :: C",
249     "Programming Language :: Cython",
250     "Topic :: Software Development :: Code Generators",
251     "Topic :: Software Development :: Compilers",
252     "Topic :: Software Development :: Libraries :: Python Modules"
253   ],
254
255   scripts = scripts,
256   packages=[
257     'Cython',
258     'Cython.Build',
259     'Cython.Compiler',
260     'Cython.Runtime',
261     'Cython.Distutils',
262     'Cython.Plex',
263
264     'Cython.Tests',
265     'Cython.Compiler.Tests',
266     ],
267
268   # pyximport
269   py_modules = ["pyximport/__init__",
270                 "pyximport/pyximport",
271                 "pyximport/pyxbuild",
272
273                 "cython"],
274
275   **setup_args
276   )