Make ghc-inplace return GHC's exitcode on Windows
[ghc-hetmet.git] / compiler / ghc-inplace.c
1
2 #include <stdio.h>
3 #include <stdarg.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7
8 #ifdef WINDOWS
9 #include <windows.h>
10 #include <process.h>
11 #include <malloc.h>
12 #include <signal.h>
13 #include <io.h>
14 #endif
15
16 int run(char *this, char *program, int argc, char **argv);
17
18 void error(const char *fmt, ...) {
19     va_list argp;
20     va_start(argp, fmt);
21     vfprintf(stderr, fmt, argp);
22     va_end(argp);
23     fprintf(stderr, "\n");
24     fflush(stderr);
25 }
26
27 int main(int argc, char **argv) {
28     char **args;
29     args = malloc(sizeof(char *) * (argc + 3));
30     if (args == NULL) {
31         fprintf(stderr, "Malloc failed\n");
32         exit(1);
33     }
34     args[0] = GHC_PATH;
35     args[1] = "-B" TOP_ABS;
36     args[2] = "-fhardwire-lib-paths";
37     if ((argc >= 2) && (strcmp(argv[1], "-v") == 0)) {
38         printf("Using %s %s %s\n", args[0], args[1], args[2]);
39     }
40     memcpy(args + 3, argv + 1, sizeof(char *) * (argc - 1));
41     args[argc+2] = NULL;
42     return run(argv[0], GHC_PATH, argc + 2, args);
43 }
44
45 #ifndef WINDOWS
46 int run(char *this, char *program, int argc, char** argv) {
47     execv(program, argv);
48     return 1; /* Not reached */
49 }
50 #else
51 int run(char *this, char *program, int argc, char** argv) {
52     TCHAR  programShort[MAX_PATH+1];
53     DWORD  dwSize;
54     DWORD  dwExitCode;
55     int    i;
56     char*  new_cmdline;
57     char   *ptr;
58     char   *src;
59     unsigned int cmdline_len;
60
61     STARTUPINFO si;
62     PROCESS_INFORMATION pi;
63   
64     ZeroMemory(&si, sizeof(STARTUPINFO));
65     ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
66
67     si.cb = sizeof(STARTUPINFO);
68
69     dwSize = MAX_PATH;
70     /* Turn the path into short form - LFN form causes problems
71        when passed in argv[0]. */
72     if ( !(GetShortPathName(program, programShort, dwSize)) ) {
73         error("%s: Unable to locate %s", this, program);
74         return 1;
75     }
76   
77     /* Compute length of the flattened 'argv', including spaces! */
78     cmdline_len = 0;
79     for(i = 1; i < argc; i++) {
80         /* Note: play it safe and quote all argv strings */
81         cmdline_len += 1 + strlen(argv[i]) + 2;
82     }
83     new_cmdline = (char*)malloc(sizeof(char) * (cmdline_len + 1));
84     if (!new_cmdline) {
85         error("%s: failed to start up ghc.exe; insufficient memory", this);
86         return 1;
87     }
88   
89     ptr = new_cmdline;
90     for(i = 1; i < argc; i++) {
91         *ptr++ = ' ';
92         *ptr++ = '"';
93         src = argv[i];
94         while(*src) {
95             *ptr++ = *src++;
96         }
97         *ptr++ = '"';
98     }
99     *ptr = '\0';
100   
101     /* Note: Used to use _spawnv(_P_WAIT, ...) here, but it suffered
102        from the parent intercepting console events such as Ctrl-C,
103        which it shouldn't. Installing an ignore-all console handler
104        didn't do the trick either.
105
106        Irrespective of this issue, using CreateProcess() is preferable,
107        as it makes this wrapper work on both mingw and cygwin.
108     */
109 #if 0
110     fprintf(stderr, "Invoking ghc: %s %s\n", programShort, new_cmdline);
111     fflush(stderr);
112 #endif
113     if (!CreateProcess(programShort,
114                        new_cmdline,
115                        NULL,
116                        NULL,
117                        TRUE,
118                        0, /* dwCreationFlags */
119                        NULL, /* lpEnvironment */
120                        NULL, /* lpCurrentDirectory */
121                        &si,  /* lpStartupInfo */
122                        &pi) ) {
123         error("%s: Unable to start ghc.exe (error code: %lu)",
124               this, GetLastError());
125         return 1;
126     }
127     /* Disable handling of console events in the parent by dropping its
128      * connection to the console. This has the (minor) downside of not being
129      * able to subsequently emit any error messages to the console.
130      */
131     FreeConsole();
132
133     switch (WaitForSingleObject(pi.hProcess, INFINITE) ) {
134         case WAIT_OBJECT_0:
135             if (GetExitCodeProcess(pi.hProcess, &dwExitCode)) {
136                 return dwExitCode;
137             }
138             else {
139                 return 1;
140             }
141         case WAIT_ABANDONED:
142         case WAIT_FAILED:
143             /* in the event we get any hard errors, bring the child
144                to a halt. */
145             TerminateProcess(pi.hProcess, 1);
146             return 1;
147         default:
148             return 1;
149     }
150 }
151 #endif
152