You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.1 KiB

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