divert cythonrun output to stderr
[cython.git] / bin / cythonrun
1 #!/usr/bin/env python
2
3 """
4 Compile a Python script into an executable that embeds CPython and run it.
5 Requires CPython to be built as a shared library ('libpythonX.Y').
6
7 Basic usage:
8
9     python cythonrun somefile.py [ARGS]
10 """
11
12 DEBUG = True
13
14 import sys
15 import os
16 import subprocess
17 from distutils import sysconfig
18
19 INCDIR = sysconfig.get_python_inc()
20 LIBDIR1 = sysconfig.get_config_var('LIBDIR')
21 LIBDIR2 = sysconfig.get_config_var('LIBPL')
22 PYLIB = sysconfig.get_config_var('LIBRARY')[3:-2]
23
24 CC = sysconfig.get_config_var('CC')
25 CFLAGS = sysconfig.get_config_var('CFLAGS') + ' ' + os.environ.get('CFLAGS', '')
26 LINKCC = sysconfig.get_config_var('LINKCC')
27 LINKFORSHARED = sysconfig.get_config_var('LINKFORSHARED')
28 LIBS = sysconfig.get_config_var('LIBS')
29 SYSLIBS = sysconfig.get_config_var('SYSLIBS')
30
31 if DEBUG:
32     def _debug(msg, *args):
33         if args:
34             msg = msg % args
35         sys.stderr.write(msg + '\n')
36 else:
37     def _debug(*args):
38         pass
39
40 _debug('INCDIR: %s', INCDIR)
41 _debug('LIBDIR1: %s', LIBDIR1)
42 _debug('LIBDIR2: %s', LIBDIR2)
43 _debug('PYLIB: %s', PYLIB)
44
45 def runcmd(cmd, shell=True):
46     if shell:
47         cmd = ' '.join(cmd)
48         _debug(cmd)
49     else:
50         _debug(' '.join(cmd))
51
52     returncode = subprocess.call(cmd, shell=shell)
53     if returncode:
54         sys.exit(returncode)
55
56 def clink(basename):
57     runcmd([LINKCC, '-o', basename, basename+'.o', '-L'+LIBDIR1, '-L'+LIBDIR2, '-l'+PYLIB]
58            + LIBS.split() + SYSLIBS.split() + LINKFORSHARED.split())
59
60 def ccompile(basename):
61     runcmd([CC, '-c', '-o', basename+'.o', basename+'.c', '-I' + INCDIR] + CFLAGS.split())
62
63 def cycompile(input_file, options=()):
64     from Cython.Compiler import Version, CmdLine, Main
65     options, sources = CmdLine.parse_command_line(list(options or ()) + ['--embed', input_file])
66     _debug('Using Cython %s to compile %s', Version.version, input_file)
67     result = Main.compile(sources, options)
68     if result.num_errors > 0:
69         sys.exit(1)
70
71 def exec_file(basename, args=()):
72     runcmd([os.path.abspath(basename)] + list(args), shell=False)
73
74 def main(args):
75     cy_args = []
76     for i, arg in enumerate(args):
77         if arg.startswith('-'):
78             cy_args.append(arg)
79         else:
80             input_file = arg
81             args = args[i+1:]
82             break
83     else:
84         raise ValueError('no input file provided')
85     basename = os.path.splitext(input_file)[0]
86     cycompile(input_file, cy_args)
87     ccompile(basename)
88     clink(basename)
89     exec_file(basename, args)
90
91 if __name__ == '__main__':
92     main(sys.argv[1:])