summaryrefslogtreecommitdiff
path: root/launcher.c
diff options
context:
space:
mode:
authorPJ Eby <distutils-sig@python.org>2005-09-17 01:13:02 +0000
committerPJ Eby <distutils-sig@python.org>2005-09-17 01:13:02 +0000
commit635f624cec403304af912b031670bcb39b6be3f0 (patch)
treeb9aa9ca6d2049ccb783d15d7aa1d72826655e399 /launcher.c
parentd5603388462585a22df0d7810261ea8556587314 (diff)
downloadpython-setuptools-bitbucket-635f624cec403304af912b031670bcb39b6be3f0.tar.gz
Added support to solve the infamous "we want .py on Windows, no
extension elsewhere" problem, while also bypassing the need for PATHEXT on Windows, and in fact the need to even write script files at all, for any platform. Instead, you define "entry points" in your setup script, in this case the names of the scripts you want (without extensions) and the functions that should be imported and run to implement the scripts. Setuptools will then generate platform-appropriate script files at install time, including an .exe wrapper when installing on Windows.
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));
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+