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.

155 lines
4.4 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. static const 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, *code_name;
  29. FILE *infile = NULL, *outfile = NULL;
  30. struct _Py_stat_struct status;
  31. size_t text_size, data_size, n;
  32. char *text = NULL;
  33. unsigned char *data;
  34. PyObject *code = NULL, *marshalled = NULL;
  35. int is_bootstrap = 1;
  36. PyImport_FrozenModules = _PyImport_FrozenModules;
  37. if (argc != 3) {
  38. fprintf(stderr, "need to specify input and output paths\n");
  39. return 2;
  40. }
  41. inpath = argv[1];
  42. outpath = argv[2];
  43. infile = fopen(inpath, "rb");
  44. if (infile == NULL) {
  45. fprintf(stderr, "cannot open '%s' for reading\n", inpath);
  46. goto error;
  47. }
  48. if (_Py_fstat_noraise(fileno(infile), &status)) {
  49. fprintf(stderr, "cannot fstat '%s'\n", inpath);
  50. goto error;
  51. }
  52. text_size = (size_t)status.st_size;
  53. text = (char *) malloc(text_size + 1);
  54. if (text == NULL) {
  55. fprintf(stderr, "could not allocate %ld bytes\n", (long) text_size);
  56. goto error;
  57. }
  58. n = fread(text, 1, text_size, infile);
  59. fclose(infile);
  60. infile = NULL;
  61. if (n < text_size) {
  62. fprintf(stderr, "read too short: got %ld instead of %ld bytes\n",
  63. (long) n, (long) text_size);
  64. goto error;
  65. }
  66. text[text_size] = '\0';
  67. Py_NoUserSiteDirectory++;
  68. Py_NoSiteFlag++;
  69. Py_IgnoreEnvironmentFlag++;
  70. Py_FrozenFlag++;
  71. Py_SetProgramName(L"./_freeze_importlib");
  72. /* Don't install importlib, since it could execute outdated bytecode. */
  73. _Py_InitializeEx_Private(1, 0);
  74. if (strstr(inpath, "_external") != NULL) {
  75. is_bootstrap = 0;
  76. }
  77. code_name = is_bootstrap ?
  78. "<frozen importlib._bootstrap>" :
  79. "<frozen importlib._bootstrap_external>";
  80. code = Py_CompileStringExFlags(text, code_name, Py_file_input, NULL, 0);
  81. if (code == NULL)
  82. goto error;
  83. free(text);
  84. text = NULL;
  85. marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION);
  86. Py_CLEAR(code);
  87. if (marshalled == NULL)
  88. goto error;
  89. assert(PyBytes_CheckExact(marshalled));
  90. data = (unsigned char *) PyBytes_AS_STRING(marshalled);
  91. data_size = PyBytes_GET_SIZE(marshalled);
  92. /* Open the file in text mode. The hg checkout should be using the eol extension,
  93. which in turn should cause the EOL style match the C library's text mode */
  94. outfile = fopen(outpath, "w");
  95. if (outfile == NULL) {
  96. fprintf(stderr, "cannot open '%s' for writing\n", outpath);
  97. goto error;
  98. }
  99. fprintf(outfile, "%s\n", header);
  100. if (is_bootstrap)
  101. fprintf(outfile, "const unsigned char _Py_M__importlib[] = {\n");
  102. else
  103. fprintf(outfile,
  104. "const unsigned char _Py_M__importlib_external[] = {\n");
  105. for (n = 0; n < data_size; n += 16) {
  106. size_t i, end = Py_MIN(n + 16, data_size);
  107. fprintf(outfile, " ");
  108. for (i = n; i < end; i++) {
  109. fprintf(outfile, "%d,", (unsigned int) data[i]);
  110. }
  111. fprintf(outfile, "\n");
  112. }
  113. fprintf(outfile, "};\n");
  114. Py_CLEAR(marshalled);
  115. Py_Finalize();
  116. if (outfile) {
  117. if (ferror(outfile)) {
  118. fprintf(stderr, "error when writing to '%s'\n", outpath);
  119. goto error;
  120. }
  121. fclose(outfile);
  122. }
  123. return 0;
  124. error:
  125. PyErr_Print();
  126. Py_Finalize();
  127. if (infile)
  128. fclose(infile);
  129. if (outfile)
  130. fclose(outfile);
  131. if (text)
  132. free(text);
  133. if (marshalled)
  134. Py_DECREF(marshalled);
  135. return 1;
  136. }