aboutsummaryrefslogtreecommitdiffstats
path: root/launcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'launcher.c')
-rwxr-xr-xlauncher.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/launcher.c b/launcher.c
new file mode 100755
index 00000000..5896805f
--- /dev/null
+++ b/launcher.c
@@ -0,0 +1,123 @@
+/*
+ Setuptools Script Launcher for Windows
+
+ This is a stub executable for Windows that functions somewhat like
+ Effbot's "exemaker", in that it runs a script with the same name but
+ a .py extension, using information from a #! line. It differs in that
+ it spawns the actual Python executable, rather than attempting to
+ hook into the Python DLL. This means that the script will run with
+ sys.executable set to the Python executable, where exemaker ends up with
+ sys.executable pointing to itself. (Which means it won't work if you try
+ to run another Python process using sys.executable.)
+
+ To build/rebuild with mingw32, do this in the setuptools project directory:
+
+ gcc -mno-cygwin -O -s -o setuptools/launcher.exe launcher.c
+
+ It links to msvcrt.dll, but this shouldn't be a problem since it doesn't
+ actually run Python in the same process. Note that using 'exec' instead
+ of 'spawn' doesn't work, because on Windows this leads to the Python
+ executable running in the *background*, attached to the same console
+ window, meaning you get a command prompt back *before* Python even finishes
+ starting. So, we have to use spawnv() and wait for Python to exit before
+ continuing. :(
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "windows.h"
+
+int fail(char *format, char *data) {
+ /* Print error message to stderr and return 1 */
+ fprintf(stderr, format, data);
+ return 1;
+}
+
+
+
+
+
+int main(int argc, char **argv) {
+
+ char python[256]; /* python executable's filename*/
+ char script[256]; /* the script's filename */
+
+ HINSTANCE hPython; /* DLL handle for python executable */
+ int scriptf; /* file descriptor for script file */
+
+ char **newargs; /* argument array for exec */
+ char *ptr, *end; /* working pointers for string manipulation */
+
+ /* compute script name from our .exe name*/
+ GetModuleFileName(NULL, script, sizeof(script));
+ end = script + strlen(script);
+ while( end>script && *end != '.')
+ *end-- = '\0';
+ strcat(script, "py");
+
+ /* figure out the target python executable */
+
+ scriptf = open(script, O_RDONLY);
+ if (scriptf == -1) {
+ return fail("Cannot open %s\n", script);
+ }
+ end = python + read(scriptf, python, sizeof(python));
+ close(scriptf);
+
+ ptr = python-1;
+ while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {
+ if (*ptr=='/')
+ *ptr='\\'; /* convert slashes to avoid LoadLibrary crashes... */
+ }
+
+ *ptr = '\0';
+ while (ptr>python && isspace(*ptr)) *ptr-- = '\0'; /* strip trailing sp */
+
+ if (strncmp(python, "#!", 2)) {
+ /* default to python.exe if no #! header */
+ strcpy(python, "#!python.exe");
+ }
+
+ /* At this point, the python buffer contains "#!pythonfilename" */
+
+ /* Using spawnv() can fail strangely if you e.g. find the Cygwin
+ Python, so we'll make sure Windows can find and load it */
+ hPython = LoadLibraryEx(python+2, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hPython) {
+ return fail("Cannot find Python executable %s\n", python+2);
+ }
+
+ /* And we'll use the absolute filename for spawnv */
+ GetModuleFileName(hPython, python, sizeof(python));
+
+ /* printf("Python executable: %s\n", python); */
+
+ /* Argument array needs to be argc+1 for args, plus 1 for null sentinel */
+ newargs = (char **)calloc(argc+2, sizeof(char *));
+ newargs[0] = python;
+ newargs[1] = script;
+ memcpy(newargs+2, argv+1, (argc-1)*sizeof(char *));
+ newargs[argc+1] = NULL;
+
+ /* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */
+
+ return spawnv(P_WAIT, newargs[0], (const char * const *)(newargs));
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+