3 * $Id: ghci.c,v 1.8 2003/06/12 09:48:17 simonpj Exp $
5 * ghci wrapper for Win32 only
7 * This wrapper invokes ghc.exe with the added command-line
8 * option "--interactive".
9 * (On Unix this is done by the ghci.sh shell script, but
10 * that does not work so well on Win32.)
12 * (c) The GHC Team 2001
14 * ghc.exe is searched for using the 'normal' search rules
15 * for DLLs / EXEs (i.e., first in the same dir as this wrapper,
16 * then system dirs, then PATH).
20 * MSVC: cl /o ghci.exe /c ghciwrap.c
21 * mingw: gcc -mno-cygwin -o ghci.exe ghciwrap.c
23 * If you want to associate your own icon with the wrapper,
24 * here's how to do it:
26 * * Create a one-line .rc file, ghci.rc (say), containing
28 * (subst the string literal for the name of your icon file).
29 * * Compile it up (assuming the .ico file is in the same dir
32 * MSVC: rc /i. /fo ghci.res ghci.rc
33 * mingw: windres -o ghci.res -i ghci.rc -O coff
35 * * Add the resulting .res file to the link line of the wrapper:
37 * MSVC: cl /o ghci.exe /c ghciwrap.c ghci.res
38 * mingw: gcc -mno-cygwin -o ghci.exe ghciwrap.c ghci.res
48 #define BINARY_NAME "ghc.exe"
49 #define IACTIVE_OPTION "--interactive"
51 #define errmsg(msg) fprintf(stderr, msg "\n"); fflush(stderr)
54 main(int argc, char** argv)
56 TCHAR binPath[FILENAME_MAX+1];
57 TCHAR binPathShort[MAX_PATH+1];
58 DWORD dwSize = FILENAME_MAX;
64 /* Locate the binary we want to start up */
74 errmsg("Unable to locate ghc.exe");
79 /* Turn the path into short form - LFN form causes problems
80 when passed in argv[0]. */
81 if ( !(GetShortPathName(binPath, binPathShort, dwSize)) ) {
82 errmsg("Unable to locate ghc.exe");
86 new_argv = (char**)malloc(sizeof(char*) * (argc + 1 + 1));
87 if (new_argv == NULL) {
88 errmsg("failed to start up ghc.exe");
91 new_argv[0] = binPathShort;
93 new_argv[1] = (char*)malloc(sizeof(char) * (strlen(IACTIVE_OPTION) + 1));
95 strcpy(new_argv[1], IACTIVE_OPTION);
97 errmsg("failed to start up ghc.exe");
101 for ( i=1; i < argc; i++ ) {
102 int len = strlen(argv[i]);
103 /* to avoid quoting issues, surround each option in double quotes */
104 new_argv[i+1] = (char*)malloc(sizeof(char) * (len + 3));
105 if (new_argv[i+1] == NULL) {
106 errmsg("failed to start up ghc.exe");
109 new_argv[i+1][0] = '"';
110 strcpy(1 + new_argv[i+1], argv[i]);
111 new_argv[i+1][len+1] = '"';
112 new_argv[i+1][len+2] = '\0';
115 new_argv[i+1] = NULL;
117 /* I was hoping to be able to use execv() here, but
118 the MS implementation of said function doesn't appear to
119 be quite right (the 'parent' app seems to exit without
120 waiting, which is not a spec-fulfilling thing to do).
122 Cygwin gives me the right behaviour, but does it by
123 implementing it in terms of spawnv(), so you pay
124 the cost of having to create an extra process.
125 Plus, of course, we aren't allowed to use Cygwin here, because
126 GHC does not assume Cygwin.
128 ==> Just use spawnv(), which is provided by msvcrt.dll, the
129 Microsoft C runtime to which mingw delegates almost all
132 [Sigbjorn adds 12 Jun 03]
133 We probably ought to use CreateProcess() in ghci.c -- or better still an exec()-like
134 that didn't have to create a separate process from the wrapper (which is what that
135 code comment in there is driving at.)
137 CreateProcess() is a more wieldy function to invoke, which is probably why
138 I opted for spawnv(). spawnv() performs the equivalent of Prelude.unwords
139 (to look at the code itself, or at least an older version, see dospawn.c in the
140 vc98/crt/src/ directory of an MSVC6 installation.)
142 CreateProcess() is a native Win32 API though, which has the merit that it is
143 guaranteed to work the same with both the mingw and cygwin ports.
146 fprintf(stderr, "Invoking ghc: ");
148 while (new_argv[i] != NULL) {
149 fprintf(stderr, "%s ", new_argv[i++]);
151 fprintf(stderr, "\n"); fflush(stderr);
153 return _spawnv(_P_WAIT, binPath, new_argv);