2 /* gcc on mingw is hardcoded to use /mingw (which is c:/mingw) to
3 find various files. If this is a different version of mingw to the
4 one that we have in the GHC tree then things can go wrong. We
5 therefore need to add various -B flags to the gcc commandline,
6 so that it uses our in-tree mingw. Hence this wrapper. */
15 void die(const char *fmt, ...) {
19 vfprintf(stderr, fmt, argp);
24 char *mkString(const char *fmt, ...) {
30 i = vsnprintf(NULL, 0, fmt, argp);
34 die("snprintf 0 failed: errno %d: %s\n", errno, strerror(errno));
39 die("malloc failed: errno %d: %s\n", errno, strerror(errno));
43 j = vsnprintf(p, i + 1, fmt, argp);
46 die("snprintf with %d failed: errno %d: %s\n",
47 i + 1, errno, strerror(errno));
53 char *flattenAndQuoteArgs(char *ptr, int argc, char *argv[])
58 for (i = 0; i < argc; i++) {
73 __attribute__((noreturn)) int run (char *exePath,
74 int numArgs1, char **args1,
75 int numArgs2, char **args2)
78 char *new_cmdline, *ptr;
81 PROCESS_INFORMATION pi;
83 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
84 ZeroMemory(&si, sizeof(STARTUPINFO));
85 si.cb = sizeof(STARTUPINFO);
87 /* Compute length of the flattened 'argv'. for each arg:
89 * + chars * 2 (accounting for possible escaping)
92 cmdline_len = 1 + strlen(exePath)*2 + 2;
93 for (i=0; i < numArgs1; i++) {
94 cmdline_len += 1 + strlen(args1[i])*2 + 2;
96 for (i=0; i < numArgs2; i++) {
97 cmdline_len += 1 + strlen(args2[i])*2 + 2;
100 new_cmdline = (char*)malloc(sizeof(char) * (cmdline_len + 1));
102 die("failed to start up %s; insufficient memory", exePath);
105 ptr = flattenAndQuoteArgs(new_cmdline, 1, &exePath);
106 ptr = flattenAndQuoteArgs(ptr, numArgs1, args1);
107 ptr = flattenAndQuoteArgs(ptr, numArgs2, args2);
108 *--ptr = '\0'; // replace the final space with \0
110 /* Note: Used to use _spawnv(_P_WAIT, ...) here, but it suffered
111 from the parent intercepting console events such as Ctrl-C,
112 which it shouldn't. Installing an ignore-all console handler
113 didn't do the trick either.
115 Irrespective of this issue, using CreateProcess() is preferable,
116 as it makes this wrapper work on both mingw and cygwin.
119 fprintf(stderr, "Invoking %s\n", new_cmdline); fflush(stderr);
121 if (!CreateProcess(exePath,
126 0, /* dwCreationFlags */
127 NULL, /* lpEnvironment */
128 NULL, /* lpCurrentDirectory */
129 &si, /* lpStartupInfo */
131 die("Unable to start %s (error code: %lu)\n", exePath, GetLastError());
133 /* Disable handling of console events in the parent by dropping its
134 * connection to the console. This has the (minor) downside of not being
135 * able to subsequently emit any error messages to the console.
139 switch (WaitForSingleObject(pi.hProcess, INFINITE) ) {
143 if (GetExitCodeProcess(pi.hProcess, &pExitCode) == 0) {
150 /* in the event we get any hard errors, bring the child to a halt. */
151 TerminateProcess(pi.hProcess,1);