cythonrun 2.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#!/usr/bin/env python

"""
Compile a Python script into an executable that embeds CPython and run it.
Requires CPython to be built as a shared library ('libpythonX.Y').

Basic usage:

    python cythonrun somefile.py [ARGS]
"""

DEBUG = True

import sys
import os
import subprocess
from distutils import sysconfig

INCDIR = sysconfig.get_python_inc()
LIBDIR1 = sysconfig.get_config_var('LIBDIR')
LIBDIR2 = sysconfig.get_config_var('LIBPL')
PYLIB = sysconfig.get_config_var('LIBRARY')[3:-2]

CC = sysconfig.get_config_var('CC')
CFLAGS = sysconfig.get_config_var('CFLAGS') + ' ' + os.environ.get('CFLAGS', '')
LINKCC = sysconfig.get_config_var('LINKCC')
LINKFORSHARED = sysconfig.get_config_var('LINKFORSHARED')
LIBS = sysconfig.get_config_var('LIBS')
SYSLIBS = sysconfig.get_config_var('SYSLIBS')

31
if DEBUG:
32 33 34 35 36 37 38 39 40 41 42 43
    def _debug(msg, *args):
        if args:
            msg = msg % args
        sys.stderr.write(msg + '\n')
else:
    def _debug(*args):
        pass

_debug('INCDIR: %s', INCDIR)
_debug('LIBDIR1: %s', LIBDIR1)
_debug('LIBDIR2: %s', LIBDIR2)
_debug('PYLIB: %s', PYLIB)
44

45
def runcmd(cmd, shell=True):
46 47
    if shell:
        cmd = ' '.join(cmd)
48
        _debug(cmd)
49
    else:
50
        _debug(' '.join(cmd))
51

52
    returncode = subprocess.call(cmd, shell=shell)
53 54 55 56 57 58 59 60 61 62
    if returncode:
        sys.exit(returncode)

def clink(basename):
    runcmd([LINKCC, '-o', basename, basename+'.o', '-L'+LIBDIR1, '-L'+LIBDIR2, '-l'+PYLIB]
           + LIBS.split() + SYSLIBS.split() + LINKFORSHARED.split())

def ccompile(basename):
    runcmd([CC, '-c', '-o', basename+'.o', basename+'.c', '-I' + INCDIR] + CFLAGS.split())

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 68 69 70
    result = Main.compile(sources, options)
    if result.num_errors > 0:
        sys.exit(1)

71
def exec_file(basename, args=()):
72 73
    runcmd([os.path.abspath(basename)] + list(args), shell=False)

74 75 76 77 78 79 80 81 82 83 84
def main(args):
    cy_args = []
    for i, arg in enumerate(args):
        if arg.startswith('-'):
            cy_args.append(arg)
        else:
            input_file = arg
            args = args[i+1:]
            break
    else:
        raise ValueError('no input file provided')
85
    basename = os.path.splitext(input_file)[0]
86
    cycompile(input_file, cy_args)
87 88
    ccompile(basename)
    clink(basename)
89
    exec_file(basename, args)
90 91

if __name__ == '__main__':
92
    main(sys.argv[1:])