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