Commits

Nick Coghlan committed 499184f

Move application source out Modules dir

  • Participants
  • Parent commits d8f417f
  • Branches pep432_modular_bootstrap

Comments (0)

Files changed (11)

 PCbuild/amd64
 BuildLog.htm
 __pycache__
-Modules/_freeze_importlib
-Modules/_testembed
+Tools/_freeze_importlib
+Tools/_testembed
 .coverage
 coverage/
 htmlcov/
 # Define dependencies of generated files that are checked into hg.
 # The syntax of this file uses make rule dependencies, without actions
 
-Python/importlib.h: Lib/importlib/_bootstrap.py Python/freeze_importlib.py
+Python/importlib.h: Lib/importlib/_bootstrap.py Tools/_freeze_importlib.c
 
 Include/ast.h: Parser/Python.asdl Parser/asdl.py Parser/asdl_c.py
 Python/Python-ast.c: Include/ast.h
 
 Python/opcode_targets.h: Python/makeopcodetargets.py Lib/opcode.py
 
-Objects/typeslots.inc: Include/typeslots.h Objects/typeslots.py
+Objects/typeslots.inc: Include/typeslots.h Objects/typeslots.py
+/* Minimal main program -- everything is loaded from the library */
+
+#include "Python.h"
+#include <locale.h>
+
+#ifdef __FreeBSD__
+#include <floatingpoint.h>
+#endif
+
+#ifdef MS_WINDOWS
+int
+wmain(int argc, wchar_t **argv)
+{
+    return Py_Main(argc, argv);
+}
+#else
+
+int
+main(int argc, char **argv)
+{
+    wchar_t **argv_copy = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1));
+    /* We need a second copies, as Python might modify the first one. */
+    wchar_t **argv_copy2 = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1));
+    int i, res;
+    char *oldloc;
+    /* 754 requires that FP exceptions run in "no stop" mode by default,
+     * and until C vendors implement C99's ways to control FP exceptions,
+     * Python requires non-stop mode.  Alas, some platforms enable FP
+     * exceptions by default.  Here we disable them.
+     */
+#ifdef __FreeBSD__
+    fp_except_t m;
+
+    m = fpgetmask();
+    fpsetmask(m & ~FP_X_OFL);
+#endif
+    if (!argv_copy || !argv_copy2) {
+        fprintf(stderr, "out of memory\n");
+        return 1;
+    }
+    oldloc = strdup(setlocale(LC_ALL, NULL));
+    setlocale(LC_ALL, "");
+    for (i = 0; i < argc; i++) {
+        argv_copy[i] = _Py_char2wchar(argv[i], NULL);
+        if (!argv_copy[i]) {
+            free(oldloc);
+            fprintf(stderr, "Fatal Python error: "
+                            "unable to decode the command line argument #%i\n",
+                            i + 1);
+            return 1;
+        }
+        argv_copy2[i] = argv_copy[i];
+    }
+    argv_copy2[argc] = argv_copy[argc] = NULL;
+
+    setlocale(LC_ALL, oldloc);
+    free(oldloc);
+    res = Py_Main(argc, argv_copy);
+    for (i = 0; i < argc; i++) {
+        PyMem_Free(argv_copy2[i]);
+    }
+    PyMem_Free(argv_copy);
+    PyMem_Free(argv_copy2);
+    return res;
+}
+#endif

Lib/test/test_capi.py

         # LookupError: no codec search functions registered: can't find encoding"
         os.chdir(basepath)
         try:
-            exe = os.path.join(basepath, "Modules", "_testembed")
+            exe = os.path.join(basepath, "Tools", "_testembed")
             if not os.path.exists(exe):
                 self.skipTest("%r doesn't exist" % exe)
             p = subprocess.Popen([exe],
 
 # Default target
 all:		build_all
-build_all:	$(BUILDPYTHON) oldsharedmods sharedmods gdbhooks Modules/_testembed
+build_all:	$(BUILDPYTHON) oldsharedmods sharedmods gdbhooks Tools/_testembed
 
 # Compile a binary with gcc profile guided optimization.
 profile-opt:
 
 
 # Build the interpreter
-$(BUILDPYTHON):	Modules/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
-	$(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Modules/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
+$(BUILDPYTHON):	Apps/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
+	$(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Apps/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
 
 platform: $(BUILDPYTHON) pybuilddir.txt
 	$(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import sys ; from sysconfig import get_platform ; print(get_platform()+"-"+sys.version[0:3])' >platform
 		echo "-----------------------------------------------"; \
 	fi
 
-Modules/_testembed: Modules/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
-	$(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Modules/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
+Tools/_testembed: Tools/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
+	$(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Tools/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
 
 ############################################################################
 # Importlib
 
-Modules/_freeze_importlib: Modules/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN)
-	$(LINKCC) $(PY_LDFLAGS) -o $@ Modules/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
+Tools/_freeze_importlib: Tools/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN)
+	$(LINKCC) $(PY_LDFLAGS) -o $@ Tools/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
 
-Python/importlib.h: $(srcdir)/Lib/importlib/_bootstrap.py Modules/_freeze_importlib.c
-	$(MAKE) Modules/_freeze_importlib
-	./Modules/_freeze_importlib \
+Python/importlib.h: $(srcdir)/Lib/importlib/_bootstrap.py Tools/_freeze_importlib.c
+	$(MAKE) Tools/_freeze_importlib
+	./Tools/_freeze_importlib \
 		$(srcdir)/Lib/importlib/_bootstrap.py Python/importlib.h
 
 
 		-DVPATH='"$(VPATH)"' \
 		-o $@ $(srcdir)/Modules/getpath.c
 
-Modules/python.o: $(srcdir)/Modules/python.c
-	$(MAINCC) -c $(PY_CORE_CFLAGS) -o $@ $(srcdir)/Modules/python.c
+Apps/python.o: $(srcdir)/Apps/python.c
+	$(MAINCC) -c $(PY_CORE_CFLAGS) -o $@ $(srcdir)/Apps/python.c
 
-Modules/_testembed.o: $(srcdir)/Modules/_testembed.c
-	$(MAINCC) -c $(PY_CORE_CFLAGS) -o $@ $(srcdir)/Modules/_testembed.c
+Tools/_testembed.o: $(srcdir)/Tools/_testembed.c
+	$(MAINCC) -c $(PY_CORE_CFLAGS) -o $@ $(srcdir)/Tools/_testembed.c
 
 Python/dynload_shlib.o: $(srcdir)/Python/dynload_shlib.c Makefile
 	$(CC) -c $(PY_CORE_CFLAGS) \
 		pyconfig.h \
 		$(PARSER_HEADERS)
 
-$(LIBRARY_OBJS) $(MODOBJS) Modules/python.o: $(PYTHON_HEADERS)
+$(LIBRARY_OBJS) $(MODOBJS) Apps/python.o: $(PYTHON_HEADERS)
 
 
 ######################################################################
 		fi; \
 	fi
 	$(INSTALL_DATA) Modules/config.c $(DESTDIR)$(LIBPL)/config.c
-	$(INSTALL_DATA) Modules/python.o $(DESTDIR)$(LIBPL)/python.o
+	$(INSTALL_DATA) Apps/python.o $(DESTDIR)$(LIBPL)/python.o
 	$(INSTALL_DATA) $(srcdir)/Modules/config.c.in $(DESTDIR)$(LIBPL)/config.c.in
 	$(INSTALL_DATA) Makefile $(DESTDIR)$(LIBPL)/Makefile
 	$(INSTALL_DATA) Modules/Setup $(DESTDIR)$(LIBPL)/Setup
 	$(INSTALL_SCRIPT) $(srcdir)/install-sh $(DESTDIR)$(LIBPL)/install-sh
 	$(INSTALL_SCRIPT) python-config $(DESTDIR)$(BINDIR)/python$(LDVERSION)-config
 	rm python-config
-	@if [ -s Modules/python.exp -a \
+	@if [ -s Apps/python.exp -a \
 		"`echo $(MACHDEP) | sed 's/^\(...\).*/\1/'`" = "aix" ]; then \
 		echo; echo "Installing support files for building shared extension modules on AIX:"; \
-		$(INSTALL_DATA) Modules/python.exp		\
+		$(INSTALL_DATA) Apps/python.exp		\
 				$(DESTDIR)$(LIBPL)/python.exp;		\
 		echo; echo "$(LIBPL)/python.exp";		\
 		$(INSTALL_SCRIPT) $(srcdir)/Modules/makexp_aix	\
 	find build -name '*.py[co]' -exec rm -f {} ';' || true
 	-rm -f pybuilddir.txt
 	-rm -f Lib/lib2to3/*Grammar*.pickle
-	-rm -f Modules/_testembed Modules/_freeze_importlib
+	-rm -f Tools/_testembed Tools/_freeze_importlib
 
 profile-removal:
 	find . -name '*.gc??' -exec rm -f {} ';'
 	done
 	-rm -f core Makefile Makefile.pre config.status \
 		Modules/Setup Modules/Setup.local Modules/Setup.config \
-		Modules/ld_so_aix Modules/python.exp Misc/python.pc
+		Modules/ld_so_aix Apps/python.exp Misc/python.pc
 	-rm -f python*-gdb.py
 	find $(srcdir) '(' -name '*.fdc' -o -name '*~' \
 			   -o -name '[@,#]*' -o -name '*.old' \

Modules/_freeze_importlib.c

-/* This is built as a stand-alone executable by the Makefile, and helps turn
-   Lib/importlib/_bootstrap.py into a frozen module in Python/importlib.h
-*/
-
-#include <Python.h>
-#include <marshal.h>
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifndef MS_WINDOWS
-#include <unistd.h>
-#endif
-
-
-/* To avoid a circular dependency on frozen.o, we create our own structure
-   of frozen modules instead, left deliberately blank so as to avoid
-   unintentional import of a stale version of _frozen_importlib. */
-
-static struct _frozen _PyImport_FrozenModules[] = {
-    {0, 0, 0} /* sentinel */
-};
-
-#ifndef MS_WINDOWS
-/* On Windows, this links with the regular pythonXY.dll, so this variable comes
-   from frozen.obj. In the Makefile, frozen.o is not linked into this executable,
-   so we define the variable here. */
-struct _frozen *PyImport_FrozenModules;
-#endif
-
-const char header[] = "/* Auto-generated by Modules/_freeze_importlib.c */";
-
-int
-main(int argc, char *argv[])
-{
-    char *inpath, *outpath;
-    FILE *infile, *outfile = NULL;
-    struct stat st;
-    size_t text_size, data_size, n;
-    char *text;
-    unsigned char *data;
-    PyObject *code, *marshalled;
-
-    PyImport_FrozenModules = _PyImport_FrozenModules;
-
-    if (argc != 3) {
-        fprintf(stderr, "need to specify input and output paths\n");
-        return 2;
-    }
-    inpath = argv[1];
-    outpath = argv[2];
-    infile = fopen(inpath, "rb");
-    if (infile == NULL) {
-        fprintf(stderr, "cannot open '%s' for reading\n", inpath);
-        return 1;
-    }
-    if (fstat(fileno(infile), &st)) {
-        fclose(infile);
-        fprintf(stderr, "cannot fstat '%s'\n", inpath);
-        return 1;
-    }
-    text_size = st.st_size;
-    text = (char *) malloc(text_size + 1);
-    if (text == NULL) {
-        fclose(infile);
-        fprintf(stderr, "could not allocate %ld bytes\n", (long) text_size);
-        return 1;
-    }
-    n = fread(text, 1, text_size, infile);
-    fclose(infile);
-    infile = NULL;
-    if (n < text_size) {
-        fprintf(stderr, "read too short: got %ld instead of %ld bytes\n",
-                (long) n, (long) text_size);
-        return 1;
-    }
-    text[text_size] = '\0';
-
-    Py_NoUserSiteDirectory++;
-    Py_NoSiteFlag++;
-    Py_IgnoreEnvironmentFlag++;
-
-    Py_SetProgramName(L"./_freeze_importlib");
-    /* Don't install importlib, since it could execute outdated bytecode. */
-    _Py_InitializeEx_Private(1, 0);
-
-    code = Py_CompileStringExFlags(text, "<frozen importlib._bootstrap>",
-                                   Py_file_input, NULL, 0);
-    if (code == NULL)
-        goto error;
-    marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION);
-    Py_DECREF(code);
-    if (marshalled == NULL)
-        goto error;
-
-    assert(PyBytes_CheckExact(marshalled));
-    data = (unsigned char *) PyBytes_AS_STRING(marshalled);
-    data_size = PyBytes_GET_SIZE(marshalled);
-
-    /* Open the file in text mode. The hg checkout should be using the eol extension,
-       which in turn should cause the EOL style match the C library's text mode */
-    outfile = fopen(outpath, "w");
-    if (outfile == NULL) {
-        fprintf(stderr, "cannot open '%s' for writing\n", outpath);
-        return 1;
-    }
-    fprintf(outfile, "%s\n", header);
-    fprintf(outfile, "unsigned char _Py_M__importlib[] = {\n");
-    for (n = 0; n < data_size; n += 16) {
-        size_t i, end = Py_MIN(n + 16, data_size);
-        fprintf(outfile, "    ");
-        for (i = n; i < end; i++) {
-            fprintf(outfile, "%d,", (unsigned int) data[i]);
-        }
-        fprintf(outfile, "\n");
-    }
-    fprintf(outfile, "};\n");
-
-    Py_DECREF(marshalled);
-
-    Py_Finalize();
-    if (infile)
-        fclose(infile);
-    if (outfile) {
-        if (ferror(outfile)) {
-            fprintf(stderr, "error when writing to '%s'\n", outpath);
-            fclose(outfile);
-            return 1;
-        }
-        fclose(outfile);
-    }
-    return 0;
-
-error:
-    PyErr_Print();
-    Py_Finalize();
-    if (infile)
-        fclose(infile);
-    if (outfile)
-        fclose(outfile);
-    return 1;
-}

Modules/_testembed.c

-#include <Python.h>
-#include <stdio.h>
-
-void print_subinterp(void)
-{
-    /* Just output some debug stuff */
-    PyThreadState *ts = PyThreadState_Get();
-    printf("interp %p, thread state %p: ", ts->interp, ts);
-    fflush(stdout);
-    PyRun_SimpleString(
-        "import sys;"
-        "print('id(modules) =', id(sys.modules));"
-        "sys.stdout.flush()"
-    );
-}
-
-int main(int argc, char *argv[])
-{
-    PyThreadState *mainstate, *substate;
-#ifdef WITH_THREAD
-    PyGILState_STATE gilstate;
-#endif
-    int i, j;
-
-    for (i=0; i<3; i++) {
-        printf("--- Pass %d ---\n", i);
-        /* HACK: the "./" at front avoids a search along the PATH in
-           Modules/getpath.c */
-        Py_SetProgramName(L"./_testembed");
-        Py_Initialize();
-        mainstate = PyThreadState_Get();
-
-#ifdef WITH_THREAD
-        PyEval_InitThreads();
-        PyEval_ReleaseThread(mainstate);
-
-        gilstate = PyGILState_Ensure();
-#endif
-        print_subinterp();
-        PyThreadState_Swap(NULL);
-
-        for (j=0; j<3; j++) {
-            substate = Py_NewInterpreter();
-            print_subinterp();
-            Py_EndInterpreter(substate);
-        }
-
-        PyThreadState_Swap(mainstate);
-        print_subinterp();
-#ifdef WITH_THREAD
-        PyGILState_Release(gilstate);
-#endif
-
-        PyEval_RestoreThread(mainstate);
-        Py_Finalize();
-    }
-    return 0;
-}

Modules/python.c

-/* Minimal main program -- everything is loaded from the library */
-
-#include "Python.h"
-#include <locale.h>
-
-#ifdef __FreeBSD__
-#include <floatingpoint.h>
-#endif
-
-#ifdef MS_WINDOWS
-int
-wmain(int argc, wchar_t **argv)
-{
-    return Py_Main(argc, argv);
-}
-#else
-
-int
-main(int argc, char **argv)
-{
-    wchar_t **argv_copy = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1));
-    /* We need a second copies, as Python might modify the first one. */
-    wchar_t **argv_copy2 = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1));
-    int i, res;
-    char *oldloc;
-    /* 754 requires that FP exceptions run in "no stop" mode by default,
-     * and until C vendors implement C99's ways to control FP exceptions,
-     * Python requires non-stop mode.  Alas, some platforms enable FP
-     * exceptions by default.  Here we disable them.
-     */
-#ifdef __FreeBSD__
-    fp_except_t m;
-
-    m = fpgetmask();
-    fpsetmask(m & ~FP_X_OFL);
-#endif
-    if (!argv_copy || !argv_copy2) {
-        fprintf(stderr, "out of memory\n");
-        return 1;
-    }
-    oldloc = strdup(setlocale(LC_ALL, NULL));
-    setlocale(LC_ALL, "");
-    for (i = 0; i < argc; i++) {
-        argv_copy[i] = _Py_char2wchar(argv[i], NULL);
-        if (!argv_copy[i]) {
-            free(oldloc);
-            fprintf(stderr, "Fatal Python error: "
-                            "unable to decode the command line argument #%i\n",
-                            i + 1);
-            return 1;
-        }
-        argv_copy2[i] = argv_copy[i];
-    }
-    argv_copy2[argc] = argv_copy[argc] = NULL;
-
-    setlocale(LC_ALL, oldloc);
-    free(oldloc);
-    res = Py_Main(argc, argv_copy);
-    for (i = 0; i < argc; i++) {
-        PyMem_Free(argv_copy2[i]);
-    }
-    PyMem_Free(argv_copy);
-    PyMem_Free(argv_copy2);
-    return res;
-}
-#endif

Python/importlib.h

-/* Auto-generated by Modules/_freeze_importlib.c */
+/* Auto-generated by Tools/_freeze_importlib */
 unsigned char _Py_M__importlib[] = {
     99,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,
     0,64,0,0,0,115,200,3,0,0,100,0,0,90,0,0,

Tools/_freeze_importlib.c

+/* This is built as a stand-alone executable by the Makefile, and helps turn
+   Lib/importlib/_bootstrap.py into a frozen module in Python/importlib.h
+*/
+
+#include <Python.h>
+#include <marshal.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef MS_WINDOWS
+#include <unistd.h>
+#endif
+
+
+/* To avoid a circular dependency on frozen.o, we create our own structure
+   of frozen modules instead, left deliberately blank so as to avoid
+   unintentional import of a stale version of _frozen_importlib. */
+
+static struct _frozen _PyImport_FrozenModules[] = {
+    {0, 0, 0} /* sentinel */
+};
+
+#ifndef MS_WINDOWS
+/* On Windows, this links with the regular pythonXY.dll, so this variable comes
+   from frozen.obj. In the Makefile, frozen.o is not linked into this executable,
+   so we define the variable here. */
+struct _frozen *PyImport_FrozenModules;
+#endif
+
+const char header[] = "/* Auto-generated by Tools/_freeze_importlib */";
+
+int
+main(int argc, char *argv[])
+{
+    char *inpath, *outpath;
+    FILE *infile, *outfile = NULL;
+    struct stat st;
+    size_t text_size, data_size, n;
+    char *text;
+    unsigned char *data;
+    PyObject *code, *marshalled;
+
+    PyImport_FrozenModules = _PyImport_FrozenModules;
+
+    if (argc != 3) {
+        fprintf(stderr, "need to specify input and output paths\n");
+        return 2;
+    }
+    inpath = argv[1];
+    outpath = argv[2];
+    infile = fopen(inpath, "rb");
+    if (infile == NULL) {
+        fprintf(stderr, "cannot open '%s' for reading\n", inpath);
+        return 1;
+    }
+    if (fstat(fileno(infile), &st)) {
+        fclose(infile);
+        fprintf(stderr, "cannot fstat '%s'\n", inpath);
+        return 1;
+    }
+    text_size = st.st_size;
+    text = (char *) malloc(text_size + 1);
+    if (text == NULL) {
+        fclose(infile);
+        fprintf(stderr, "could not allocate %ld bytes\n", (long) text_size);
+        return 1;
+    }
+    n = fread(text, 1, text_size, infile);
+    fclose(infile);
+    infile = NULL;
+    if (n < text_size) {
+        fprintf(stderr, "read too short: got %ld instead of %ld bytes\n",
+                (long) n, (long) text_size);
+        return 1;
+    }
+    text[text_size] = '\0';
+
+    Py_NoUserSiteDirectory++;
+    Py_NoSiteFlag++;
+    Py_IgnoreEnvironmentFlag++;
+
+    Py_SetProgramName(L"./_freeze_importlib");
+    /* Don't install importlib, since it could execute outdated bytecode. */
+    _Py_InitializeEx_Private(1, 0);
+
+    code = Py_CompileStringExFlags(text, "<frozen importlib._bootstrap>",
+                                   Py_file_input, NULL, 0);
+    if (code == NULL)
+        goto error;
+    marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION);
+    Py_DECREF(code);
+    if (marshalled == NULL)
+        goto error;
+
+    assert(PyBytes_CheckExact(marshalled));
+    data = (unsigned char *) PyBytes_AS_STRING(marshalled);
+    data_size = PyBytes_GET_SIZE(marshalled);
+
+    /* Open the file in text mode. The hg checkout should be using the eol extension,
+       which in turn should cause the EOL style match the C library's text mode */
+    outfile = fopen(outpath, "w");
+    if (outfile == NULL) {
+        fprintf(stderr, "cannot open '%s' for writing\n", outpath);
+        return 1;
+    }
+    fprintf(outfile, "%s\n", header);
+    fprintf(outfile, "unsigned char _Py_M__importlib[] = {\n");
+    for (n = 0; n < data_size; n += 16) {
+        size_t i, end = Py_MIN(n + 16, data_size);
+        fprintf(outfile, "    ");
+        for (i = n; i < end; i++) {
+            fprintf(outfile, "%d,", (unsigned int) data[i]);
+        }
+        fprintf(outfile, "\n");
+    }
+    fprintf(outfile, "};\n");
+
+    Py_DECREF(marshalled);
+
+    Py_Finalize();
+    if (infile)
+        fclose(infile);
+    if (outfile) {
+        if (ferror(outfile)) {
+            fprintf(stderr, "error when writing to '%s'\n", outpath);
+            fclose(outfile);
+            return 1;
+        }
+        fclose(outfile);
+    }
+    return 0;
+
+error:
+    PyErr_Print();
+    Py_Finalize();
+    if (infile)
+        fclose(infile);
+    if (outfile)
+        fclose(outfile);
+    return 1;
+}

Tools/_testembed.c

+#include <Python.h>
+#include <stdio.h>
+
+void print_subinterp(void)
+{
+    /* Just output some debug stuff */
+    PyThreadState *ts = PyThreadState_Get();
+    printf("interp %p, thread state %p: ", ts->interp, ts);
+    fflush(stdout);
+    PyRun_SimpleString(
+        "import sys;"
+        "print('id(modules) =', id(sys.modules));"
+        "sys.stdout.flush()"
+    );
+}
+
+int main(int argc, char *argv[])
+{
+    PyThreadState *mainstate, *substate;
+#ifdef WITH_THREAD
+    PyGILState_STATE gilstate;
+#endif
+    int i, j;
+
+    for (i=0; i<3; i++) {
+        printf("--- Pass %d ---\n", i);
+        /* HACK: the "./" at front avoids a search along the PATH in
+           Modules/getpath.c */
+        Py_SetProgramName(L"./_testembed");
+        Py_Initialize();
+        mainstate = PyThreadState_Get();
+
+#ifdef WITH_THREAD
+        PyEval_InitThreads();
+        PyEval_ReleaseThread(mainstate);
+
+        gilstate = PyGILState_Ensure();
+#endif
+        print_subinterp();
+        PyThreadState_Swap(NULL);
+
+        for (j=0; j<3; j++) {
+            substate = Py_NewInterpreter();
+            print_subinterp();
+            Py_EndInterpreter(substate);
+        }
+
+        PyThreadState_Swap(mainstate);
+        print_subinterp();
+#ifdef WITH_THREAD
+        PyGILState_Release(gilstate);
+#endif
+
+        PyEval_RestoreThread(mainstate);
+        Py_Finalize();
+    }
+    return 0;
+}