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