1#!/usr/bin/env python 2""" 3Create a C file for embedding one or more Cython source files. 4Requires Cython 0.11.2 (or perhaps newer). 5 6See Demos/freeze/README.txt for more details. 7""" 8 9import optparse 10from os.path import splitext, basename 11 12usage= '%prog [-o outfile] [-p] module [module ...]' 13description = 'Create a C file for embedding Cython modules.' 14p = optparse.OptionParser(usage=usage, description=description) 15p.add_option('-o', '--output', metavar='FILE', 16 help='write output to FILE instead of standard output') 17p.add_option('-p', '--pymain', action='store_true', default=False, 18 help='do not automatically run the first module as __main__') 19 20options, args = p.parse_args() 21 22if len(args) < 1: 23 p.print_help() 24 p.exit(1) 25 26if options.output: 27 import sys 28 old_stdout = sys.stdout 29 sys.stdout = open(options.output, 'w') 30 31modules = [basename(splitext(x)[0]).replace('.', '_') for x in args] 32 33print """\ 34#include <Python.h> 35#include <locale.h> 36#include <stdio.h> 37#include <stdlib.h> 38 39#ifdef __FreeBSD__ 40#include <floatingpoint.h> 41#endif 42 43#if PY_MAJOR_VERSION < 3 44# define MODINIT(name) init ## name 45#else 46# define MODINIT(name) PyInit_ ## name 47#endif 48""" 49 50for name in modules: 51 print "PyMODINIT_FUNC MODINIT(%s) (void);" % name 52 53print """ 54static struct _inittab inittab[] = {""" 55 56for name in modules: 57 print ' {"%(name)s", MODINIT(%(name)s)},' % {'name' : name} 58 59print """ {NULL, NULL} 60}; 61""", 62 63if not options.pymain: 64 print "\nextern int __pyx_module_is_main_%s;" % modules[0] 65 66print """ 67#if PY_MAJOR_VERSION < 3 68int main(int argc, char** argv) { 69#elif defined(WIN32) || defined(MS_WINDOWS) 70int wmain(int argc, wchar_t **argv) { 71#else 72static int python_main(int argc, wchar_t **argv) { 73#endif 74""", 75if not options.pymain: 76 print """\ 77 PyObject *m = NULL; 78 int r = 0; 79""", 80print """\ 81 /* 754 requires that FP exceptions run in "no stop" mode by default, 82 * and until C vendors implement C99's ways to control FP exceptions, 83 * Python requires non-stop mode. Alas, some platforms enable FP 84 * exceptions by default. Here we disable them. 85 */ 86#ifdef __FreeBSD__ 87 fp_except_t m; 88 89 m = fpgetmask(); 90 fpsetmask(m & ~FP_X_OFL); 91#endif 92 if (PyImport_ExtendInittab(inittab)) { 93 fprintf(stderr, "No memory\\n"); 94 exit(1); 95 } 96""", 97if options.pymain: 98 print """\ 99 return Py_Main(argc, argv); 100} 101""" 102else: 103 print """\ 104 Py_SetProgramName(argv[0]); 105 Py_Initialize(); 106 PySys_SetArgv(argc, argv); 107 __pyx_module_is_main_%(main)s = 1; 108 m = PyImport_ImportModule(inittab[0].name); 109 if (!m) { 110 r = 1; 111 PyErr_Print(); /* This exits with the right code if SystemExit. */ 112#if PY_MAJOR_VERSION < 3 113 if (Py_FlushLine()) 114 PyErr_Clear(); 115#endif 116 } 117 Py_XDECREF(m); 118 Py_Finalize(); 119 return r; 120} 121""" % {'main' : modules[0]}, 122 123print r""" 124#if PY_MAJOR_VERSION >= 3 && !defined(WIN32) && !defined(MS_WINDOWS) 125static wchar_t* 126char2wchar(char* arg) 127{ 128 wchar_t *res; 129#ifdef HAVE_BROKEN_MBSTOWCS 130 /* Some platforms have a broken implementation of 131 * mbstowcs which does not count the characters that 132 * would result from conversion. Use an upper bound. 133 */ 134 size_t argsize = strlen(arg); 135#else 136 size_t argsize = mbstowcs(NULL, arg, 0); 137#endif 138 size_t count; 139 unsigned char *in; 140 wchar_t *out; 141#ifdef HAVE_MBRTOWC 142 mbstate_t mbs; 143#endif 144 if (argsize != (size_t)-1) { 145 res = (wchar_t *)malloc((argsize+1)*sizeof(wchar_t)); 146 if (!res) 147 goto oom; 148 count = mbstowcs(res, arg, argsize+1); 149 if (count != (size_t)-1) { 150 wchar_t *tmp; 151 /* Only use the result if it contains no 152 surrogate characters. */ 153 for (tmp = res; *tmp != 0 && 154 (*tmp < 0xd800 || *tmp > 0xdfff); tmp++) 155 ; 156 if (*tmp == 0) 157 return res; 158 } 159 free(res); 160 } 161 /* Conversion failed. Fall back to escaping with surrogateescape. */ 162#ifdef HAVE_MBRTOWC 163 /* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */ 164 165 /* Overallocate; as multi-byte characters are in the argument, the 166 actual output could use less memory. */ 167 argsize = strlen(arg) + 1; 168 res = malloc(argsize*sizeof(wchar_t)); 169 if (!res) goto oom; 170 in = (unsigned char*)arg; 171 out = res; 172 memset(&mbs, 0, sizeof mbs); 173 while (argsize) { 174 size_t converted = mbrtowc(out, (char*)in, argsize, &mbs); 175 if (converted == 0) 176 /* Reached end of string; null char stored. */ 177 break; 178 if (converted == (size_t)-2) { 179 /* Incomplete character. This should never happen, 180 since we provide everything that we have - 181 unless there is a bug in the C library, or I 182 misunderstood how mbrtowc works. */ 183 fprintf(stderr, "unexpected mbrtowc result -2\n"); 184 return NULL; 185 } 186 if (converted == (size_t)-1) { 187 /* Conversion error. Escape as UTF-8b, and start over 188 in the initial shift state. */ 189 *out++ = 0xdc00 + *in++; 190 argsize--; 191 memset(&mbs, 0, sizeof mbs); 192 continue; 193 } 194 if (*out >= 0xd800 && *out <= 0xdfff) { 195 /* Surrogate character. Escape the original 196 byte sequence with surrogateescape. */ 197 argsize -= converted; 198 while (converted--) 199 *out++ = 0xdc00 + *in++; 200 continue; 201 } 202 /* successfully converted some bytes */ 203 in += converted; 204 argsize -= converted; 205 out++; 206 } 207#else 208 /* Cannot use C locale for escaping; manually escape as if charset 209 is ASCII (i.e. escape all bytes > 128. This will still roundtrip 210 correctly in the locale's charset, which must be an ASCII superset. */ 211 res = malloc((strlen(arg)+1)*sizeof(wchar_t)); 212 if (!res) goto oom; 213 in = (unsigned char*)arg; 214 out = res; 215 while(*in) 216 if(*in < 128) 217 *out++ = *in++; 218 else 219 *out++ = 0xdc00 + *in++; 220 *out = 0; 221#endif 222 return res; 223oom: 224 fprintf(stderr, "out of memory\n"); 225 return NULL; 226} 227 228int 229main(int argc, char **argv) 230{ 231 wchar_t **argv_copy = (wchar_t **)malloc(sizeof(wchar_t*)*argc); 232 /* We need a second copies, as Python might modify the first one. */ 233 wchar_t **argv_copy2 = (wchar_t **)malloc(sizeof(wchar_t*)*argc); 234 int i, res; 235 char *oldloc; 236 if (!argv_copy || !argv_copy2) { 237 fprintf(stderr, "out of memory\n"); 238 return 1; 239 } 240 oldloc = strdup(setlocale(LC_ALL, NULL)); 241 setlocale(LC_ALL, ""); 242 for (i = 0; i < argc; i++) { 243 argv_copy2[i] = argv_copy[i] = char2wchar(argv[i]); 244 if (!argv_copy[i]) 245 return 1; 246 } 247 setlocale(LC_ALL, oldloc); 248 free(oldloc); 249 res = python_main(argc, argv_copy); 250 for (i = 0; i < argc; i++) { 251 free(argv_copy2[i]); 252 } 253 free(argv_copy); 254 free(argv_copy2); 255 return res; 256} 257#endif""" 258