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