Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 1 | /* This is built as a stand-alone executable by the Makefile, and helps turn |
| 2 | Lib/importlib/_bootstrap.py into a frozen module in Python/importlib.h |
| 3 | */ |
| 4 | |
| 5 | #include <Python.h> |
| 6 | #include <marshal.h> |
| 7 | |
| 8 | #include <stdio.h> |
| 9 | #include <sys/types.h> |
| 10 | #include <sys/stat.h> |
Martin v. Löwis | 96d97ec | 2012-07-28 20:46:52 +0200 | [diff] [blame] | 11 | #ifndef MS_WINDOWS |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 12 | #include <unistd.h> |
Martin v. Löwis | 96d97ec | 2012-07-28 20:46:52 +0200 | [diff] [blame] | 13 | #endif |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 14 | |
| 15 | |
| 16 | /* To avoid a circular dependency on frozen.o, we create our own structure |
| 17 | of frozen modules instead, left deliberately blank so as to avoid |
| 18 | unintentional import of a stale version of _frozen_importlib. */ |
| 19 | |
| 20 | static struct _frozen _PyImport_FrozenModules[] = { |
| 21 | {0, 0, 0} /* sentinel */ |
| 22 | }; |
| 23 | |
Martin v. Löwis | ee365ac | 2012-07-28 21:55:20 +0200 | [diff] [blame] | 24 | #ifndef MS_WINDOWS |
| 25 | /* On Windows, this links with the regular pythonXY.dll, so this variable comes |
| 26 | from frozen.obj. In the Makefile, frozen.o is not linked into this executable, |
| 27 | so we define the variable here. */ |
| 28 | struct _frozen *PyImport_FrozenModules; |
| 29 | #endif |
| 30 | |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 31 | const char header[] = "/* Auto-generated by Modules/_freeze_importlib.c */"; |
| 32 | |
| 33 | int |
| 34 | main(int argc, char *argv[]) |
| 35 | { |
| 36 | char *inpath, *outpath; |
| 37 | FILE *infile, *outfile = NULL; |
| 38 | struct stat st; |
| 39 | size_t text_size, data_size, n; |
Antoine Pitrou | 0ab5cf9 | 2012-06-25 17:32:43 +0200 | [diff] [blame] | 40 | char *text; |
| 41 | unsigned char *data; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 42 | PyObject *code, *marshalled; |
| 43 | |
Martin v. Löwis | 96d97ec | 2012-07-28 20:46:52 +0200 | [diff] [blame] | 44 | PyImport_FrozenModules = _PyImport_FrozenModules; |
| 45 | |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 46 | if (argc != 3) { |
| 47 | fprintf(stderr, "need to specify input and output paths\n"); |
| 48 | return 2; |
| 49 | } |
| 50 | inpath = argv[1]; |
| 51 | outpath = argv[2]; |
| 52 | infile = fopen(inpath, "rb"); |
| 53 | if (infile == NULL) { |
| 54 | fprintf(stderr, "cannot open '%s' for reading\n", inpath); |
| 55 | return 1; |
| 56 | } |
| 57 | if (fstat(fileno(infile), &st)) { |
| 58 | fclose(infile); |
| 59 | fprintf(stderr, "cannot fstat '%s'\n", inpath); |
| 60 | return 1; |
| 61 | } |
| 62 | text_size = st.st_size; |
| 63 | text = (char *) malloc(text_size + 1); |
| 64 | if (text == NULL) { |
| 65 | fclose(infile); |
| 66 | fprintf(stderr, "could not allocate %ld bytes\n", (long) text_size); |
| 67 | return 1; |
| 68 | } |
| 69 | n = fread(text, 1, text_size, infile); |
| 70 | fclose(infile); |
| 71 | infile = NULL; |
| 72 | if (n < text_size) { |
| 73 | fprintf(stderr, "read too short: got %ld instead of %ld bytes\n", |
| 74 | (long) n, (long) text_size); |
| 75 | return 1; |
| 76 | } |
| 77 | text[text_size] = '\0'; |
| 78 | |
| 79 | Py_NoUserSiteDirectory++; |
| 80 | Py_NoSiteFlag++; |
| 81 | Py_IgnoreEnvironmentFlag++; |
| 82 | |
| 83 | Py_SetProgramName(L"./_freeze_importlib"); |
| 84 | /* Don't install importlib, since it could execute outdated bytecode. */ |
| 85 | _Py_InitializeEx_Private(1, 0); |
| 86 | |
| 87 | code = Py_CompileStringExFlags(text, "<frozen importlib._bootstrap>", |
| 88 | Py_file_input, NULL, 0); |
| 89 | if (code == NULL) |
| 90 | goto error; |
| 91 | marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION); |
| 92 | Py_DECREF(code); |
| 93 | if (marshalled == NULL) |
| 94 | goto error; |
| 95 | |
| 96 | assert(PyBytes_CheckExact(marshalled)); |
Antoine Pitrou | 0ab5cf9 | 2012-06-25 17:32:43 +0200 | [diff] [blame] | 97 | data = (unsigned char *) PyBytes_AS_STRING(marshalled); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 98 | data_size = PyBytes_GET_SIZE(marshalled); |
| 99 | |
Martin v. Löwis | 96d97ec | 2012-07-28 20:46:52 +0200 | [diff] [blame] | 100 | /* Open the file in text mode. The hg checkout should be using the eol extension, |
Martin v. Löwis | ee365ac | 2012-07-28 21:55:20 +0200 | [diff] [blame] | 101 | which in turn should cause the EOL style match the C library's text mode */ |
| 102 | outfile = fopen(outpath, "w"); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 103 | if (outfile == NULL) { |
| 104 | fprintf(stderr, "cannot open '%s' for writing\n", outpath); |
| 105 | return 1; |
| 106 | } |
| 107 | fprintf(outfile, "%s\n", header); |
| 108 | fprintf(outfile, "unsigned char _Py_M__importlib[] = {\n"); |
| 109 | for (n = 0; n < data_size; n += 16) { |
| 110 | size_t i, end = Py_MIN(n + 16, data_size); |
| 111 | fprintf(outfile, " "); |
| 112 | for (i = n; i < end; i++) { |
Antoine Pitrou | 0ab5cf9 | 2012-06-25 17:32:43 +0200 | [diff] [blame] | 113 | fprintf(outfile, "%d,", (unsigned int) data[i]); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 114 | } |
| 115 | fprintf(outfile, "\n"); |
| 116 | } |
| 117 | fprintf(outfile, "};\n"); |
| 118 | |
| 119 | Py_DECREF(marshalled); |
| 120 | |
| 121 | Py_Finalize(); |
| 122 | if (infile) |
| 123 | fclose(infile); |
| 124 | if (outfile) { |
| 125 | if (ferror(outfile)) { |
| 126 | fprintf(stderr, "error when writing to '%s'\n", outpath); |
| 127 | fclose(outfile); |
| 128 | return 1; |
| 129 | } |
| 130 | fclose(outfile); |
| 131 | } |
| 132 | return 0; |
| 133 | |
| 134 | error: |
| 135 | PyErr_Print(); |
| 136 | Py_Finalize(); |
| 137 | if (infile) |
| 138 | fclose(infile); |
| 139 | if (outfile) |
| 140 | fclose(outfile); |
| 141 | return 1; |
| 142 | } |