diff --git a/Demos/freeze/Makefile b/Demos/freeze/Makefile index d108182789f78fac569ddd02fc070ec0d147d169..51ab3bd80528c458a83158e1d3a7fcc45d224d6b 100644 --- a/Demos/freeze/Makefile +++ b/Demos/freeze/Makefile @@ -1,17 +1,20 @@ CC = gcc -CYTHON = ../../bin/cython -CYTHON_FREEZE = ../../bin/cython_freeze +CYTHON = cython +CYTHON_FREEZE = ./cython_freeze PYTHON = python RST2HTML = rst2html PY_LDFLAGS = $(shell $(PYTHON) -c 'from distutils.sysconfig import get_config_var as g; import sys; sys.stdout.write(" ".join([g("LINKFORSHARED"), "-L"+g("LIBPL")]) + "\n")') PY_CPPFLAGS = $(shell $(PYTHON) -c 'from distutils.sysconfig import *; import sys; sys.stdout.write("-I"+get_python_inc() + "\n")') -PY_LDLIBS = $(shell $(PYTHON) -c 'from distutils.sysconfig import get_config_var as g; import sys; sys.stdout.write(" ".join(["-lpython"+g("VERSION"), g("SYSLIBS"), g("LIBS"), g("LOCALMODLIBS")]) + "\n")') +LIBDIR1 := $(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_config_var('LIBDIR'))") +LIBDIR2 := $(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_config_var('LIBPL'))") +PYLIB := $(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_config_var('LIBRARY')[3:-2])") +LIBS := $(shell $(PYTHON) -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBS'))") CFLAGS = -fPIC -fno-strict-aliasing -g -O2 -Wall -Wextra CPPFLAGS = $(PY_CPPFLAGS) LDFLAGS = $(PY_LDFLAGS) -LDLIBS = $(PY_LDLIBS) +LDLIBS = -L$(LIBDIR1) -L$(LIBDIR2) -l$(PYLIB) # Name of executable diff --git a/Demos/freeze/cython_freeze b/Demos/freeze/cython_freeze new file mode 100755 index 0000000000000000000000000000000000000000..4be33b69a2cad41ba988d1ac48d3de911958fbf4 --- /dev/null +++ b/Demos/freeze/cython_freeze @@ -0,0 +1,258 @@ +#!/usr/bin/env python +""" +Create a C file for embedding one or more Cython source files. +Requires Cython 0.11.2 (or perhaps newer). + +See Demos/freeze/README.txt for more details. +""" +from __future__ import print_function + +import optparse +from os.path import splitext, basename + +usage= '%prog [-o outfile] [-p] module [module ...]' +description = 'Create a C file for embedding Cython modules.' +p = optparse.OptionParser(usage=usage, description=description) +p.add_option('-o', '--output', metavar='FILE', + help='write output to FILE instead of standard output') +p.add_option('-p', '--pymain', action='store_true', default=False, + help='do not automatically run the first module as __main__') + +options, args = p.parse_args() + +if len(args) < 1: + p.print_help() + p.exit(1) + +if options.output: + import sys + old_stdout = sys.stdout + sys.stdout = open(options.output, 'w') + +modules = [basename(splitext(x)[0]).replace('.', '_') for x in args] + +print("""\ +#include <Python.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> + +#ifdef __FreeBSD__ +#include <floatingpoint.h> +#endif + +#if PY_MAJOR_VERSION < 3 +# define MODINIT(name) init ## name +#else +# define MODINIT(name) PyInit_ ## name +#endif +""") + +for name in modules: + print("PyMODINIT_FUNC MODINIT(%s) (void);" % name) + +print(""" +static struct _inittab inittab[] = {""") + +for name in modules: + print(' {"%(name)s", MODINIT(%(name)s)},' % {'name' : name}) + +print(""" {NULL, NULL} +}; +""", end=' ') + +if not options.pymain: + print("\nextern int __pyx_module_is_main_%s;" % modules[0]) + +print(""" +#if PY_MAJOR_VERSION < 3 +int main(int argc, char** argv) { +#elif defined(WIN32) || defined(MS_WINDOWS) +int wmain(int argc, wchar_t **argv) { +#else +static int python_main(int argc, wchar_t **argv) { +#endif +""", end=' ') +if not options.pymain: + print("""\ + PyObject *m = NULL; + int r = 0; +""", end=' ') +print("""\ + /* 754 requires that FP exceptions run in "no stop" mode by default, + * and until C vendors implement C99's ways to control FP exceptions, + * Python requires non-stop mode. Alas, some platforms enable FP + * exceptions by default. Here we disable them. + */ +#ifdef __FreeBSD__ + fp_except_t m; + + m = fpgetmask(); + fpsetmask(m & ~FP_X_OFL); +#endif + if (PyImport_ExtendInittab(inittab)) { + fprintf(stderr, "No memory\\n"); + exit(1); + } +""", end=' ') +if options.pymain: + print("""\ + return Py_Main(argc, argv); +} +""") +else: + print("""\ + Py_SetProgramName(argv[0]); + Py_Initialize(); + PySys_SetArgv(argc, argv); + __pyx_module_is_main_%(main)s = 1; + m = PyImport_ImportModule(inittab[0].name); + if (!m) { + r = 1; + PyErr_Print(); /* This exits with the right code if SystemExit. */ +#if PY_MAJOR_VERSION < 3 + if (Py_FlushLine()) + PyErr_Clear(); +#endif + } + Py_XDECREF(m); + Py_Finalize(); + return r; +} +""" % {'main' : modules[0]}, end=' ') + +print(r""" +#if PY_MAJOR_VERSION >= 3 && !defined(WIN32) && !defined(MS_WINDOWS) +static wchar_t* +char2wchar(char* arg) +{ + wchar_t *res; +#ifdef HAVE_BROKEN_MBSTOWCS + /* Some platforms have a broken implementation of + * mbstowcs which does not count the characters that + * would result from conversion. Use an upper bound. + */ + size_t argsize = strlen(arg); +#else + size_t argsize = mbstowcs(NULL, arg, 0); +#endif + size_t count; + unsigned char *in; + wchar_t *out; +#ifdef HAVE_MBRTOWC + mbstate_t mbs; +#endif + if (argsize != (size_t)-1) { + res = (wchar_t *)malloc((argsize+1)*sizeof(wchar_t)); + if (!res) + goto oom; + count = mbstowcs(res, arg, argsize+1); + if (count != (size_t)-1) { + wchar_t *tmp; + /* Only use the result if it contains no + surrogate characters. */ + for (tmp = res; *tmp != 0 && + (*tmp < 0xd800 || *tmp > 0xdfff); tmp++) + ; + if (*tmp == 0) + return res; + } + free(res); + } + /* Conversion failed. Fall back to escaping with surrogateescape. */ +#ifdef HAVE_MBRTOWC + /* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */ + + /* Overallocate; as multi-byte characters are in the argument, the + actual output could use less memory. */ + argsize = strlen(arg) + 1; + res = malloc(argsize*sizeof(wchar_t)); + if (!res) goto oom; + in = (unsigned char*)arg; + out = res; + memset(&mbs, 0, sizeof mbs); + while (argsize) { + size_t converted = mbrtowc(out, (char*)in, argsize, &mbs); + if (converted == 0) + /* Reached end of string; null char stored. */ + break; + if (converted == (size_t)-2) { + /* Incomplete character. This should never happen, + since we provide everything that we have - + unless there is a bug in the C library, or I + misunderstood how mbrtowc works. */ + fprintf(stderr, "unexpected mbrtowc result -2\n"); + return NULL; + } + if (converted == (size_t)-1) { + /* Conversion error. Escape as UTF-8b, and start over + in the initial shift state. */ + *out++ = 0xdc00 + *in++; + argsize--; + memset(&mbs, 0, sizeof mbs); + continue; + } + if (*out >= 0xd800 && *out <= 0xdfff) { + /* Surrogate character. Escape the original + byte sequence with surrogateescape. */ + argsize -= converted; + while (converted--) + *out++ = 0xdc00 + *in++; + continue; + } + /* successfully converted some bytes */ + in += converted; + argsize -= converted; + out++; + } +#else + /* Cannot use C locale for escaping; manually escape as if charset + is ASCII (i.e. escape all bytes > 128. This will still roundtrip + correctly in the locale's charset, which must be an ASCII superset. */ + res = malloc((strlen(arg)+1)*sizeof(wchar_t)); + if (!res) goto oom; + in = (unsigned char*)arg; + out = res; + while(*in) + if(*in < 128) + *out++ = *in++; + else + *out++ = 0xdc00 + *in++; + *out = 0; +#endif + return res; +oom: + fprintf(stderr, "out of memory\n"); + return NULL; +} + +int +main(int argc, char **argv) +{ + wchar_t **argv_copy = (wchar_t **)malloc(sizeof(wchar_t*)*argc); + /* We need a second copies, as Python might modify the first one. */ + wchar_t **argv_copy2 = (wchar_t **)malloc(sizeof(wchar_t*)*argc); + int i, res; + char *oldloc; + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + return 1; + } + oldloc = strdup(setlocale(LC_ALL, NULL)); + setlocale(LC_ALL, ""); + for (i = 0; i < argc; i++) { + argv_copy2[i] = argv_copy[i] = char2wchar(argv[i]); + if (!argv_copy[i]) + return 1; + } + setlocale(LC_ALL, oldloc); + free(oldloc); + res = python_main(argc, argv_copy); + for (i = 0; i < argc; i++) { + free(argv_copy2[i]); + } + free(argv_copy); + free(argv_copy2); + return res; +} +#endif""")