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