summaryrefslogtreecommitdiff
path: root/compiler/ghc-inplace.c
blob: d7599ea2f86a1c6520477bd3540112f3bbe002cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifdef WINDOWS
#include <windows.h>
#include <process.h>
#include <malloc.h>
#include <signal.h>
#include <io.h>
#endif

int run(char *this, char *program, int argc, char **argv);

void error(const char *fmt, ...) {
    va_list argp;
    va_start(argp, fmt);
    vfprintf(stderr, fmt, argp);
    va_end(argp);
    fprintf(stderr, "\n");
    fflush(stderr);
}

int main(int argc, char **argv) {
    char **args;
    args = malloc(sizeof(char *) * (argc + 3));
    if (args == NULL) {
        fprintf(stderr, "Malloc failed\n");
        exit(1);
    }
    args[0] = "GHC_PATH"; /* Gets replaced by sed */
    args[1] = "-BTOP_ABS"; /* Gets replaced by sed */
    args[2] = "-fhardwire-lib-paths";
    if ((argc >= 2) && (strcmp(argv[1], "-v") == 0)) {
        printf("Using %s %s %s\n", args[0], args[1], args[2]);
        fflush(stdout);
    }
    memcpy(args + 3, argv + 1, sizeof(char *) * (argc - 1));
    args[argc+2] = NULL;
    return run(argv[0],
               "GHC_PATH", /* Gets replaced by sed */
               argc + 2,
               args);
}

#ifndef WINDOWS
int run(char *this, char *program, int argc, char** argv) {
    execv(program, argv);
    return 1; /* Not reached */
}
#else
int run(char *this, char *program, int argc, char** argv) {
    TCHAR  programShort[MAX_PATH+1];
    DWORD  dwSize;
    DWORD  dwExitCode;
    int    i;
    char*  new_cmdline;
    char   *ptr;
    char   *src;
    unsigned int cmdline_len;

    STARTUPINFO si;
    PROCESS_INFORMATION pi;
  
    ZeroMemory(&si, sizeof(STARTUPINFO));
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

    si.cb = sizeof(STARTUPINFO);

    dwSize = MAX_PATH;
    /* Turn the path into short form - LFN form causes problems
       when passed in argv[0]. */
    if ( !(GetShortPathName(program, programShort, dwSize)) ) {
        error("%s: Unable to locate %s", this, program);
        return 1;
    }
  
    /* Compute length of the flattened 'argv', including spaces! */
    cmdline_len = 0;
    for(i = 1; i < argc; i++) {
        /* Note: play it safe and quote all argv strings */
        cmdline_len += 1 + strlen(argv[i]) + 2;
    }
    new_cmdline = (char*)malloc(sizeof(char) * (cmdline_len + 1));
    if (!new_cmdline) {
        error("%s: failed to start up ghc.exe; insufficient memory", this);
        return 1;
    }
  
    ptr = new_cmdline;
    for(i = 1; i < argc; i++) {
        *ptr++ = ' ';
        *ptr++ = '"';
        src = argv[i];
        while(*src) {
            *ptr++ = *src++;
        }
        *ptr++ = '"';
    }
    *ptr = '\0';
  
    /* Note: Used to use _spawnv(_P_WAIT, ...) here, but it suffered
       from the parent intercepting console events such as Ctrl-C,
       which it shouldn't. Installing an ignore-all console handler
       didn't do the trick either.

       Irrespective of this issue, using CreateProcess() is preferable,
       as it makes this wrapper work on both mingw and cygwin.
    */
#if 0
    fprintf(stderr, "Invoking ghc: %s %s\n", programShort, new_cmdline);
    fflush(stderr);
#endif
    if (!CreateProcess(programShort,
                       new_cmdline,
                       NULL,
                       NULL,
                       TRUE,
                       0, /* dwCreationFlags */
                       NULL, /* lpEnvironment */
                       NULL, /* lpCurrentDirectory */
                       &si,  /* lpStartupInfo */
                       &pi) ) {
        error("%s: Unable to start ghc.exe (error code: %lu)",
              this, GetLastError());
        return 1;
    }
    /* Disable handling of console events in the parent by dropping its
     * connection to the console. This has the (minor) downside of not being
     * able to subsequently emit any error messages to the console.
     */
    FreeConsole();

    switch (WaitForSingleObject(pi.hProcess, INFINITE) ) {
        case WAIT_OBJECT_0:
            if (GetExitCodeProcess(pi.hProcess, &dwExitCode)) {
                return dwExitCode;
            }
            else {
                return 1;
            }
        case WAIT_ABANDONED:
        case WAIT_FAILED:
            /* in the event we get any hard errors, bring the child
               to a halt. */
            TerminateProcess(pi.hProcess, 1);
            return 1;
        default:
            return 1;
    }
}
#endif