Home | History | Annotate | Download | only in bin
      1 #!/usr/bin/env python
      2 """
      3 Create a C file for embedding one or more Cython source files.
      4 Requires Cython 0.11.2 (or perhaps newer).
      5 
      6 See Demos/freeze/README.txt for more details.
      7 """
      8 
      9 import optparse
     10 from os.path import splitext, basename
     11 
     12 usage= '%prog [-o outfile] [-p] module [module ...]'
     13 description = 'Create a C file for embedding Cython modules.'
     14 p = optparse.OptionParser(usage=usage, description=description)
     15 p.add_option('-o', '--output', metavar='FILE',
     16         help='write output to FILE instead of standard output')
     17 p.add_option('-p', '--pymain', action='store_true', default=False,
     18         help='do not automatically run the first module as __main__')
     19 
     20 options, args = p.parse_args()
     21 
     22 if len(args) < 1:
     23     p.print_help()
     24     p.exit(1)
     25 
     26 if options.output:
     27     import sys
     28     old_stdout = sys.stdout
     29     sys.stdout = open(options.output, 'w')
     30 
     31 modules = [basename(splitext(x)[0]).replace('.', '_') for x in args]
     32 
     33 print """\
     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 
     50 for name in modules:
     51     print "PyMODINIT_FUNC MODINIT(%s) (void);" % name
     52 
     53 print """
     54 static struct _inittab inittab[] = {"""
     55 
     56 for name in modules:
     57     print '    {"%(name)s", MODINIT(%(name)s)},' % {'name' : name}
     58 
     59 print """    {NULL, NULL}
     60 };
     61 """,
     62 
     63 if not options.pymain:
     64     print "\nextern int __pyx_module_is_main_%s;" % modules[0]
     65 
     66 print """
     67 #if PY_MAJOR_VERSION < 3
     68 int main(int argc, char** argv) {
     69 #elif defined(WIN32) || defined(MS_WINDOWS)
     70 int wmain(int argc, wchar_t **argv) {
     71 #else
     72 static int python_main(int argc, wchar_t **argv) {
     73 #endif
     74 """,
     75 if not options.pymain:
     76     print """\
     77     PyObject *m = NULL;
     78     int r = 0;
     79 """,
     80 print """\
     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 """,
     97 if options.pymain:
     98     print """\
     99     return Py_Main(argc, argv);
    100 }
    101 """
    102 else:
    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 
    123 print r"""
    124 #if PY_MAJOR_VERSION >= 3 && !defined(WIN32) && !defined(MS_WINDOWS)
    125 static wchar_t*
    126 char2wchar(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;
    223 oom:
    224 	fprintf(stderr, "out of memory\n");
    225 	return NULL;
    226 }
    227 
    228 int
    229 main(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