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