#!/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. """ import optparse 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') def format_modname(name): if name.endswith('.pyx'): name = name[:-4] elif name.endswith('.py'): name = name[:-3] return name.replace('.','_') modules = [format_modname(x) for x in args] print """\ #include #include #include #include #ifdef __FreeBSD__ #include #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} }; """, 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 """, if not options.pymain: print """\ PyObject *m = NULL; int r = 0; """, 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); } """, 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]}, 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"""