From 973fe0ba7adb081b81f319b924f9bbb50b2b1345 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Fri, 25 Jul 2014 21:52:14 +1000 Subject: Issue #18093: Factor out the programs that embed the runtime --- .gitignore | 4 +- .hgignore | 4 +- .hgtouch | 2 +- Makefile.pre.in | 40 ++++----- Modules/README | 2 + Modules/_freeze_importlib.c | 144 ------------------------------ Modules/_testembed.c | 140 ----------------------------- Modules/python.c | 77 ---------------- Objects/README | 1 + PCbuild/_freeze_importlib.vcxproj | 4 +- PCbuild/_freeze_importlib.vcxproj.filters | 4 +- PCbuild/python.vcxproj | 2 +- PCbuild/python.vcxproj.filters | 4 +- Programs/README | 1 + Programs/_freeze_importlib.c | 144 ++++++++++++++++++++++++++++++ Programs/_testembed.c | 140 +++++++++++++++++++++++++++++ Programs/python.c | 77 ++++++++++++++++ Python/README | 1 + 18 files changed, 398 insertions(+), 393 deletions(-) create mode 100644 Modules/README delete mode 100644 Modules/_freeze_importlib.c delete mode 100644 Modules/_testembed.c delete mode 100644 Modules/python.c create mode 100644 Objects/README create mode 100644 Programs/README create mode 100644 Programs/_freeze_importlib.c create mode 100644 Programs/_testembed.c create mode 100644 Programs/python.c create mode 100644 Python/README diff --git a/.gitignore b/.gitignore index 59d3832..2454870 100644 --- a/.gitignore +++ b/.gitignore @@ -27,8 +27,8 @@ Modules/Setup.config Modules/Setup.local Modules/config.c Modules/ld_so_aix -Modules/_freeze_importlib -Modules/_testembed +Programs/_freeze_importlib +Programs/_testembed PCbuild/*.bsc PCbuild/*.dll PCbuild/*.exe diff --git a/.hgignore b/.hgignore index 4dc93c4..562dac9 100644 --- a/.hgignore +++ b/.hgignore @@ -89,8 +89,8 @@ Tools/unicode/build/ Tools/unicode/MAPPINGS/ BuildLog.htm __pycache__ -Modules/_freeze_importlib -Modules/_testembed +Programs/_freeze_importlib +Programs/_testembed .coverage coverage/ htmlcov/ diff --git a/.hgtouch b/.hgtouch index 00efbef..b9be0f1 100644 --- a/.hgtouch +++ b/.hgtouch @@ -2,7 +2,7 @@ # 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 Modules/_freeze_importlib.c +Python/importlib.h: Lib/importlib/_bootstrap.py Programs/_freeze_importlib.c Include/opcode.h: Lib/opcode.py Tools/scripts/generate_opcode_h.py diff --git a/Makefile.pre.in b/Makefile.pre.in index 43bc818..03875ef 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -466,7 +466,7 @@ LIBRARY_OBJS= \ # Default target all: build_all -build_all: $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks Modules/_testembed python-config +build_all: $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks Programs/_testembed python-config # Compile a binary with gcc profile guided optimization. profile-opt: @@ -539,8 +539,8 @@ clinic: $(BUILDPYTHON) $(RUNSHARED) $(PYTHON_FOR_BUILD) ./Tools/clinic/clinic.py --make # Build the interpreter -$(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) - $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Modules/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) +$(BUILDPYTHON): Programs/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) + $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/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 @@ -665,18 +665,18 @@ Modules/Setup: $(srcdir)/Modules/Setup.dist echo "-----------------------------------------------"; \ fi -Modules/_testembed: Modules/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) - $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Modules/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) +Programs/_testembed: Programs/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) + $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_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) +Programs/_freeze_importlib: Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) + $(LINKCC) $(PY_LDFLAGS) -o $@ Programs/_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 Programs/_freeze_importlib.c + $(MAKE) Programs/_freeze_importlib + ./Programs/_freeze_importlib \ $(srcdir)/Lib/importlib/_bootstrap.py Python/importlib.h @@ -704,11 +704,11 @@ Modules/getpath.o: $(srcdir)/Modules/getpath.c Makefile -DVPATH='"$(VPATH)"' \ -o $@ $(srcdir)/Modules/getpath.c -Modules/python.o: $(srcdir)/Modules/python.c - $(MAINCC) -c $(PY_CORE_CFLAGS) -o $@ $(srcdir)/Modules/python.c +Programs/python.o: $(srcdir)/Programs/python.c + $(MAINCC) -c $(PY_CORE_CFLAGS) -o $@ $(srcdir)/Programs/python.c -Modules/_testembed.o: $(srcdir)/Modules/_testembed.c - $(MAINCC) -c $(PY_CORE_CFLAGS) -o $@ $(srcdir)/Modules/_testembed.c +Programs/_testembed.o: $(srcdir)/Programs/_testembed.c + $(MAINCC) -c $(PY_CORE_CFLAGS) -o $@ $(srcdir)/Programs/_testembed.c Modules/_sre.o: $(srcdir)/Modules/_sre.c $(srcdir)/Modules/sre.h $(srcdir)/Modules/sre_constants.h $(srcdir)/Modules/sre_lib.h @@ -922,7 +922,7 @@ PYTHON_HEADERS= \ $(PARSER_HEADERS) \ $(AST_H) -$(LIBRARY_OBJS) $(MODOBJS) Modules/python.o: $(PYTHON_HEADERS) +$(LIBRARY_OBJS) $(MODOBJS) Programs/python.o: $(PYTHON_HEADERS) ###################################################################### @@ -1332,7 +1332,7 @@ libainstall: all python-config fi; \ fi $(INSTALL_DATA) Modules/config.c $(DESTDIR)$(LIBPL)/config.c - $(INSTALL_DATA) Modules/python.o $(DESTDIR)$(LIBPL)/python.o + $(INSTALL_DATA) Programs/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 @@ -1343,10 +1343,10 @@ libainstall: all python-config $(INSTALL_SCRIPT) $(srcdir)/install-sh $(DESTDIR)$(LIBPL)/install-sh $(INSTALL_SCRIPT) python-config.py $(DESTDIR)$(LIBPL)/python-config.py $(INSTALL_SCRIPT) python-config $(DESTDIR)$(BINDIR)/python$(LDVERSION)-config - @if [ -s Modules/python.exp -a \ + @if [ -s Programs/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) Programs/python.exp \ $(DESTDIR)$(LIBPL)/python.exp; \ echo; echo "$(LIBPL)/python.exp"; \ $(INSTALL_SCRIPT) $(srcdir)/Modules/makexp_aix \ @@ -1526,7 +1526,7 @@ clean: pycremoval 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 Programs/_testembed Programs/_freeze_importlib profile-removal: find . -name '*.gc??' -exec rm -f {} ';' @@ -1550,7 +1550,7 @@ distclean: clobber 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 Programs/python.exp Misc/python.pc -rm -f python*-gdb.py find $(srcdir)/[a-zA-Z]* '(' -name '*.fdc' -o -name '*~' \ -o -name '[@,#]*' -o -name '*.old' \ diff --git a/Modules/README b/Modules/README new file mode 100644 index 0000000..9b79f53 --- /dev/null +++ b/Modules/README @@ -0,0 +1,2 @@ +Source files for standard library extension modules, +and former extension modules that are now builtin modules. diff --git a/Modules/_freeze_importlib.c b/Modules/_freeze_importlib.c deleted file mode 100644 index 57b1ac0..0000000 --- a/Modules/_freeze_importlib.c +++ /dev/null @@ -1,144 +0,0 @@ -/* 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 -#include - -#include -#include -#include -#ifndef MS_WINDOWS -#include -#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. */ - -const 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. */ -const 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 = NULL, *outfile = NULL; - struct stat st; - size_t text_size, data_size, n; - char *text = NULL; - unsigned char *data; - PyObject *code = NULL, *marshalled = NULL; - - 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); - goto error; - } - if (fstat(fileno(infile), &st)) { - fprintf(stderr, "cannot fstat '%s'\n", inpath); - goto error; - } - text_size = st.st_size; - text = (char *) malloc(text_size + 1); - if (text == NULL) { - fprintf(stderr, "could not allocate %ld bytes\n", (long) text_size); - goto error; - } - 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); - goto error; - } - 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, "", - Py_file_input, NULL, 0); - if (code == NULL) - goto error; - free(text); - text = NULL; - - marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION); - Py_CLEAR(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); - goto error; - } - fprintf(outfile, "%s\n", header); - fprintf(outfile, "const 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_CLEAR(marshalled); - - Py_Finalize(); - if (outfile) { - if (ferror(outfile)) { - fprintf(stderr, "error when writing to '%s'\n", outpath); - goto error; - } - fclose(outfile); - } - return 0; - -error: - PyErr_Print(); - Py_Finalize(); - if (infile) - fclose(infile); - if (outfile) - fclose(outfile); - if (text) - free(text); - if (marshalled) - Py_DECREF(marshalled); - return 1; -} diff --git a/Modules/_testembed.c b/Modules/_testembed.c deleted file mode 100644 index 39ff097..0000000 --- a/Modules/_testembed.c +++ /dev/null @@ -1,140 +0,0 @@ -#include -#include - -/********************************************************* - * Embedded interpreter tests that need a custom exe - * - * Executed via 'EmbeddingTests' in Lib/test/test_capi.py - *********************************************************/ - -static void _testembed_Py_Initialize(void) -{ - /* HACK: the "./" at front avoids a search along the PATH in - Modules/getpath.c */ - Py_SetProgramName(L"./_testembed"); - Py_Initialize(); -} - - -/***************************************************** - * Test repeated initalisation and subinterpreters - *****************************************************/ - -static 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()" - ); -} - -static void test_repeated_init_and_subinterpreters(void) -{ - PyThreadState *mainstate, *substate; -#ifdef WITH_THREAD - PyGILState_STATE gilstate; -#endif - int i, j; - - for (i=0; i<3; i++) { - printf("--- Pass %d ---\n", i); - _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(); - } -} - -/***************************************************** - * Test forcing a particular IO encoding - *****************************************************/ - -static void check_stdio_details(const char *encoding, const char * errors) -{ - /* Output info for the test case to check */ - if (encoding) { - printf("Expected encoding: %s\n", encoding); - } else { - printf("Expected encoding: default\n"); - } - if (errors) { - printf("Expected errors: %s\n", errors); - } else { - printf("Expected errors: default\n"); - } - fflush(stdout); - /* Force the given IO encoding */ - Py_SetStandardStreamEncoding(encoding, errors); - _testembed_Py_Initialize(); - PyRun_SimpleString( - "import sys;" - "print('stdin: {0.encoding}:{0.errors}'.format(sys.stdin));" - "print('stdout: {0.encoding}:{0.errors}'.format(sys.stdout));" - "print('stderr: {0.encoding}:{0.errors}'.format(sys.stderr));" - "sys.stdout.flush()" - ); - Py_Finalize(); -} - -static void test_forced_io_encoding(void) -{ - /* Check various combinations */ - printf("--- Use defaults ---\n"); - check_stdio_details(NULL, NULL); - printf("--- Set errors only ---\n"); - check_stdio_details(NULL, "ignore"); - printf("--- Set encoding only ---\n"); - check_stdio_details("latin-1", NULL); - printf("--- Set encoding and errors ---\n"); - check_stdio_details("latin-1", "replace"); - - /* Check calling after initialization fails */ - Py_Initialize(); - - if (Py_SetStandardStreamEncoding(NULL, NULL) == 0) { - printf("Unexpected success calling Py_SetStandardStreamEncoding"); - } - Py_Finalize(); -} - -/* Different embedding tests */ -int main(int argc, char *argv[]) -{ - - /* TODO: Check the argument string to allow for more test cases */ - if (argc > 1) { - /* For now: assume "forced_io_encoding */ - test_forced_io_encoding(); - } else { - /* Run the original embedding test case by default */ - test_repeated_init_and_subinterpreters(); - } - return 0; -} diff --git a/Modules/python.c b/Modules/python.c deleted file mode 100644 index 9811c01..0000000 --- a/Modules/python.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Minimal main program -- everything is loaded from the library */ - -#include "Python.h" -#include - -#ifdef __FreeBSD__ -#include -#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; - /* We need a second copy, as Python might modify the first one. */ - wchar_t **argv_copy2; - int i, res; - char *oldloc; -#ifdef __FreeBSD__ - fp_except_t m; -#endif - - argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); - argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); - if (!argv_copy || !argv_copy2) { - fprintf(stderr, "out of memory\n"); - return 1; - } - - /* 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__ - m = fpgetmask(); - fpsetmask(m & ~FP_X_OFL); -#endif - - oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); - if (!oldloc) { - fprintf(stderr, "out of memory\n"); - return 1; - } - - setlocale(LC_ALL, ""); - for (i = 0; i < argc; i++) { - argv_copy[i] = _Py_char2wchar(argv[i], NULL); - if (!argv_copy[i]) { - PyMem_RawFree(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); - PyMem_RawFree(oldloc); - res = Py_Main(argc, argv_copy); - for (i = 0; i < argc; i++) { - PyMem_RawFree(argv_copy2[i]); - } - PyMem_RawFree(argv_copy); - PyMem_RawFree(argv_copy2); - return res; -} -#endif diff --git a/Objects/README b/Objects/README new file mode 100644 index 0000000..854b103 --- /dev/null +++ b/Objects/README @@ -0,0 +1 @@ +Source files for various builtin objects diff --git a/PCbuild/_freeze_importlib.vcxproj b/PCbuild/_freeze_importlib.vcxproj index 55197af..e133e02 100644 --- a/PCbuild/_freeze_importlib.vcxproj +++ b/PCbuild/_freeze_importlib.vcxproj @@ -167,7 +167,7 @@ - + @@ -185,4 +185,4 @@ - \ No newline at end of file + diff --git a/PCbuild/_freeze_importlib.vcxproj.filters b/PCbuild/_freeze_importlib.vcxproj.filters index 50ec193..ccad053 100644 --- a/PCbuild/_freeze_importlib.vcxproj.filters +++ b/PCbuild/_freeze_importlib.vcxproj.filters @@ -15,7 +15,7 @@ - + Source Files @@ -24,4 +24,4 @@ Source Files - \ No newline at end of file + diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj index 5387343..6cb4ef5 100644 --- a/PCbuild/python.vcxproj +++ b/PCbuild/python.vcxproj @@ -510,7 +510,7 @@ echo @"$(OutDir)python$(PyDebugExt).exe" %%*>> "$(SolutionDir)..\python.ba - + diff --git a/PCbuild/python.vcxproj.filters b/PCbuild/python.vcxproj.filters index e4906a4..0662a4e 100644 --- a/PCbuild/python.vcxproj.filters +++ b/PCbuild/python.vcxproj.filters @@ -19,8 +19,8 @@ - + Source Files - \ No newline at end of file + diff --git a/Programs/README b/Programs/README new file mode 100644 index 0000000..c24578b --- /dev/null +++ b/Programs/README @@ -0,0 +1 @@ +Source files for binary executables (as opposed to shared modules) diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c new file mode 100644 index 0000000..57b1ac0 --- /dev/null +++ b/Programs/_freeze_importlib.c @@ -0,0 +1,144 @@ +/* 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 +#include + +#include +#include +#include +#ifndef MS_WINDOWS +#include +#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. */ + +const 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. */ +const 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 = NULL, *outfile = NULL; + struct stat st; + size_t text_size, data_size, n; + char *text = NULL; + unsigned char *data; + PyObject *code = NULL, *marshalled = NULL; + + 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); + goto error; + } + if (fstat(fileno(infile), &st)) { + fprintf(stderr, "cannot fstat '%s'\n", inpath); + goto error; + } + text_size = st.st_size; + text = (char *) malloc(text_size + 1); + if (text == NULL) { + fprintf(stderr, "could not allocate %ld bytes\n", (long) text_size); + goto error; + } + 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); + goto error; + } + 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, "", + Py_file_input, NULL, 0); + if (code == NULL) + goto error; + free(text); + text = NULL; + + marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION); + Py_CLEAR(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); + goto error; + } + fprintf(outfile, "%s\n", header); + fprintf(outfile, "const 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_CLEAR(marshalled); + + Py_Finalize(); + if (outfile) { + if (ferror(outfile)) { + fprintf(stderr, "error when writing to '%s'\n", outpath); + goto error; + } + fclose(outfile); + } + return 0; + +error: + PyErr_Print(); + Py_Finalize(); + if (infile) + fclose(infile); + if (outfile) + fclose(outfile); + if (text) + free(text); + if (marshalled) + Py_DECREF(marshalled); + return 1; +} diff --git a/Programs/_testembed.c b/Programs/_testembed.c new file mode 100644 index 0000000..39ff097 --- /dev/null +++ b/Programs/_testembed.c @@ -0,0 +1,140 @@ +#include +#include + +/********************************************************* + * Embedded interpreter tests that need a custom exe + * + * Executed via 'EmbeddingTests' in Lib/test/test_capi.py + *********************************************************/ + +static void _testembed_Py_Initialize(void) +{ + /* HACK: the "./" at front avoids a search along the PATH in + Modules/getpath.c */ + Py_SetProgramName(L"./_testembed"); + Py_Initialize(); +} + + +/***************************************************** + * Test repeated initalisation and subinterpreters + *****************************************************/ + +static 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()" + ); +} + +static void test_repeated_init_and_subinterpreters(void) +{ + PyThreadState *mainstate, *substate; +#ifdef WITH_THREAD + PyGILState_STATE gilstate; +#endif + int i, j; + + for (i=0; i<3; i++) { + printf("--- Pass %d ---\n", i); + _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(); + } +} + +/***************************************************** + * Test forcing a particular IO encoding + *****************************************************/ + +static void check_stdio_details(const char *encoding, const char * errors) +{ + /* Output info for the test case to check */ + if (encoding) { + printf("Expected encoding: %s\n", encoding); + } else { + printf("Expected encoding: default\n"); + } + if (errors) { + printf("Expected errors: %s\n", errors); + } else { + printf("Expected errors: default\n"); + } + fflush(stdout); + /* Force the given IO encoding */ + Py_SetStandardStreamEncoding(encoding, errors); + _testembed_Py_Initialize(); + PyRun_SimpleString( + "import sys;" + "print('stdin: {0.encoding}:{0.errors}'.format(sys.stdin));" + "print('stdout: {0.encoding}:{0.errors}'.format(sys.stdout));" + "print('stderr: {0.encoding}:{0.errors}'.format(sys.stderr));" + "sys.stdout.flush()" + ); + Py_Finalize(); +} + +static void test_forced_io_encoding(void) +{ + /* Check various combinations */ + printf("--- Use defaults ---\n"); + check_stdio_details(NULL, NULL); + printf("--- Set errors only ---\n"); + check_stdio_details(NULL, "ignore"); + printf("--- Set encoding only ---\n"); + check_stdio_details("latin-1", NULL); + printf("--- Set encoding and errors ---\n"); + check_stdio_details("latin-1", "replace"); + + /* Check calling after initialization fails */ + Py_Initialize(); + + if (Py_SetStandardStreamEncoding(NULL, NULL) == 0) { + printf("Unexpected success calling Py_SetStandardStreamEncoding"); + } + Py_Finalize(); +} + +/* Different embedding tests */ +int main(int argc, char *argv[]) +{ + + /* TODO: Check the argument string to allow for more test cases */ + if (argc > 1) { + /* For now: assume "forced_io_encoding */ + test_forced_io_encoding(); + } else { + /* Run the original embedding test case by default */ + test_repeated_init_and_subinterpreters(); + } + return 0; +} diff --git a/Programs/python.c b/Programs/python.c new file mode 100644 index 0000000..9811c01 --- /dev/null +++ b/Programs/python.c @@ -0,0 +1,77 @@ +/* Minimal main program -- everything is loaded from the library */ + +#include "Python.h" +#include + +#ifdef __FreeBSD__ +#include +#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; + /* We need a second copy, as Python might modify the first one. */ + wchar_t **argv_copy2; + int i, res; + char *oldloc; +#ifdef __FreeBSD__ + fp_except_t m; +#endif + + argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); + argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + return 1; + } + + /* 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__ + m = fpgetmask(); + fpsetmask(m & ~FP_X_OFL); +#endif + + oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); + if (!oldloc) { + fprintf(stderr, "out of memory\n"); + return 1; + } + + setlocale(LC_ALL, ""); + for (i = 0; i < argc; i++) { + argv_copy[i] = _Py_char2wchar(argv[i], NULL); + if (!argv_copy[i]) { + PyMem_RawFree(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); + PyMem_RawFree(oldloc); + res = Py_Main(argc, argv_copy); + for (i = 0; i < argc; i++) { + PyMem_RawFree(argv_copy2[i]); + } + PyMem_RawFree(argv_copy); + PyMem_RawFree(argv_copy2); + return res; +} +#endif diff --git a/Python/README b/Python/README new file mode 100644 index 0000000..153b628 --- /dev/null +++ b/Python/README @@ -0,0 +1 @@ +Miscellaneous source files for the main Python shared library -- cgit v0.12