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 | |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 15 | /* To avoid a circular dependency on frozen.o, we create our own structure |
| 16 | of frozen modules instead, left deliberately blank so as to avoid |
| 17 | unintentional import of a stale version of _frozen_importlib. */ |
| 18 | |
Serhiy Storchaka | b48af34 | 2015-02-26 15:27:57 +0200 | [diff] [blame] | 19 | static const struct _frozen _PyImport_FrozenModules[] = { |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 20 | {0, 0, 0} /* sentinel */ |
| 21 | }; |
| 22 | |
Martin v. Löwis | ee365ac | 2012-07-28 21:55:20 +0200 | [diff] [blame] | 23 | #ifndef MS_WINDOWS |
| 24 | /* On Windows, this links with the regular pythonXY.dll, so this variable comes |
| 25 | from frozen.obj. In the Makefile, frozen.o is not linked into this executable, |
| 26 | so we define the variable here. */ |
Benjamin Peterson | 7701e6e | 2013-03-13 14:06:39 -0500 | [diff] [blame] | 27 | const struct _frozen *PyImport_FrozenModules; |
Martin v. Löwis | ee365ac | 2012-07-28 21:55:20 +0200 | [diff] [blame] | 28 | #endif |
| 29 | |
Berker Peksag | da8cef4 | 2014-11-24 23:26:08 +0200 | [diff] [blame] | 30 | const char header[] = "/* Auto-generated by Programs/_freeze_importlib.c */"; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 31 | |
| 32 | int |
| 33 | main(int argc, char *argv[]) |
| 34 | { |
Eric Snow | 32439d6 | 2015-05-02 19:15:18 -0600 | [diff] [blame] | 35 | char *inpath, *outpath, *code_name; |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 36 | FILE *infile = NULL, *outfile = NULL; |
Victor Stinner | e134a7f | 2015-03-30 10:09:31 +0200 | [diff] [blame] | 37 | struct _Py_stat_struct status; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 38 | size_t text_size, data_size, n; |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 39 | char *text = NULL; |
Antoine Pitrou | 0ab5cf9 | 2012-06-25 17:32:43 +0200 | [diff] [blame] | 40 | unsigned char *data; |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 41 | PyObject *code = NULL, *marshalled = NULL; |
Eric Snow | 32439d6 | 2015-05-02 19:15:18 -0600 | [diff] [blame] | 42 | int is_bootstrap = 1; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 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); |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 55 | goto error; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 56 | } |
Victor Stinner | e134a7f | 2015-03-30 10:09:31 +0200 | [diff] [blame] | 57 | if (_Py_fstat_noraise(fileno(infile), &status)) { |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 58 | fprintf(stderr, "cannot fstat '%s'\n", inpath); |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 59 | goto error; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 60 | } |
Steve Dower | a439191 | 2016-09-06 19:09:15 -0700 | [diff] [blame] | 61 | text_size = (size_t)status.st_size; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 62 | text = (char *) malloc(text_size + 1); |
| 63 | if (text == NULL) { |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 64 | fprintf(stderr, "could not allocate %ld bytes\n", (long) text_size); |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 65 | goto error; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 66 | } |
| 67 | n = fread(text, 1, text_size, infile); |
| 68 | fclose(infile); |
| 69 | infile = NULL; |
| 70 | if (n < text_size) { |
| 71 | fprintf(stderr, "read too short: got %ld instead of %ld bytes\n", |
| 72 | (long) n, (long) text_size); |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 73 | goto error; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 74 | } |
| 75 | text[text_size] = '\0'; |
| 76 | |
| 77 | Py_NoUserSiteDirectory++; |
| 78 | Py_NoSiteFlag++; |
| 79 | Py_IgnoreEnvironmentFlag++; |
Ned Deily | 17cfc86 | 2016-08-19 22:12:06 -0400 | [diff] [blame] | 80 | Py_FrozenFlag++; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 81 | |
| 82 | Py_SetProgramName(L"./_freeze_importlib"); |
| 83 | /* Don't install importlib, since it could execute outdated bytecode. */ |
| 84 | _Py_InitializeEx_Private(1, 0); |
| 85 | |
Eric Snow | 32439d6 | 2015-05-02 19:15:18 -0600 | [diff] [blame] | 86 | if (strstr(inpath, "_external") != NULL) { |
| 87 | is_bootstrap = 0; |
| 88 | } |
| 89 | |
| 90 | code_name = is_bootstrap ? |
| 91 | "<frozen importlib._bootstrap>" : |
| 92 | "<frozen importlib._bootstrap_external>"; |
| 93 | code = Py_CompileStringExFlags(text, code_name, Py_file_input, NULL, 0); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 94 | if (code == NULL) |
| 95 | goto error; |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 96 | free(text); |
| 97 | text = NULL; |
| 98 | |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 99 | marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION); |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 100 | Py_CLEAR(code); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 101 | if (marshalled == NULL) |
| 102 | goto error; |
| 103 | |
| 104 | assert(PyBytes_CheckExact(marshalled)); |
Antoine Pitrou | 0ab5cf9 | 2012-06-25 17:32:43 +0200 | [diff] [blame] | 105 | data = (unsigned char *) PyBytes_AS_STRING(marshalled); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 106 | data_size = PyBytes_GET_SIZE(marshalled); |
| 107 | |
Martin v. Löwis | 96d97ec | 2012-07-28 20:46:52 +0200 | [diff] [blame] | 108 | /* 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] | 109 | which in turn should cause the EOL style match the C library's text mode */ |
| 110 | outfile = fopen(outpath, "w"); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 111 | if (outfile == NULL) { |
| 112 | fprintf(stderr, "cannot open '%s' for writing\n", outpath); |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 113 | goto error; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 114 | } |
| 115 | fprintf(outfile, "%s\n", header); |
Eric Snow | 32439d6 | 2015-05-02 19:15:18 -0600 | [diff] [blame] | 116 | if (is_bootstrap) |
| 117 | fprintf(outfile, "const unsigned char _Py_M__importlib[] = {\n"); |
| 118 | else |
| 119 | fprintf(outfile, |
| 120 | "const unsigned char _Py_M__importlib_external[] = {\n"); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 121 | for (n = 0; n < data_size; n += 16) { |
| 122 | size_t i, end = Py_MIN(n + 16, data_size); |
| 123 | fprintf(outfile, " "); |
| 124 | for (i = n; i < end; i++) { |
Antoine Pitrou | 0ab5cf9 | 2012-06-25 17:32:43 +0200 | [diff] [blame] | 125 | fprintf(outfile, "%d,", (unsigned int) data[i]); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 126 | } |
| 127 | fprintf(outfile, "\n"); |
| 128 | } |
| 129 | fprintf(outfile, "};\n"); |
| 130 | |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 131 | Py_CLEAR(marshalled); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 132 | |
| 133 | Py_Finalize(); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 134 | if (outfile) { |
| 135 | if (ferror(outfile)) { |
| 136 | fprintf(stderr, "error when writing to '%s'\n", outpath); |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 137 | goto error; |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 138 | } |
| 139 | fclose(outfile); |
| 140 | } |
| 141 | return 0; |
| 142 | |
| 143 | error: |
| 144 | PyErr_Print(); |
| 145 | Py_Finalize(); |
| 146 | if (infile) |
| 147 | fclose(infile); |
| 148 | if (outfile) |
| 149 | fclose(outfile); |
Christian Heimes | 43d82df | 2013-07-21 23:05:04 +0200 | [diff] [blame] | 150 | if (text) |
| 151 | free(text); |
| 152 | if (marshalled) |
| 153 | Py_DECREF(marshalled); |
Antoine Pitrou | e67f48c | 2012-06-19 22:29:35 +0200 | [diff] [blame] | 154 | return 1; |
| 155 | } |