1
/* ----------------------------------------------------------------------------
4
* This is used to fix limitations within nmake and the environment.
6
* Copyright (c) 2002 by David Gravereaux.
8
* See the file "license.terms" for information on usage and redistribution
9
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11
* ----------------------------------------------------------------------------
12
* RCS: @(#) $Id: nmakehlp.c,v 1.1 2002/03/27 21:15:43 davygrvy Exp $
13
* ----------------------------------------------------------------------------
16
#pragma comment (lib, "user32.lib")
17
#pragma comment (lib, "kernel32.lib")
20
int CheckForCompilerFeature (const char *option);
21
int CheckForLinkerFeature (const char *option);
22
int IsIn (const char *string, const char *substring);
23
DWORD WINAPI ReadFromPipe (LPVOID args);
31
pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'};
32
pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'};
36
/* exitcodes: 0 == no, 1 == yes, 2 == error */
38
main (int argc, char *argv[])
44
if (argc > 1 && *argv[1] == '-') {
45
switch (*(argv[1]+1)) {
48
chars = wsprintf(msg, "usage: %s -c <compiler option>\n"
49
"Tests for whether cl.exe supports an option\n"
50
"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
51
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
54
return CheckForCompilerFeature(argv[2]);
57
chars = wsprintf(msg, "usage: %s -l <linker option>\n"
58
"Tests for whether link.exe supports an option\n"
59
"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
60
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
63
return CheckForLinkerFeature(argv[2]);
66
chars = wsprintf(msg, "usage: %s -f <string> <substring>\n"
67
"Find a substring within another\n"
68
"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
69
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
71
} else if (argc == 3) {
72
/* if the string is blank, there is no match */
75
return IsIn(argv[2], argv[3]);
79
chars = wsprintf(msg, "usage: %s -c|-l|-f ...\n"
80
"This is a little helper app to equalize shell differences between WinNT and\n"
81
"Win9x and get nmake.exe to accomplish its job.\n",
83
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
88
CheckForCompilerFeature (const char *option)
91
PROCESS_INFORMATION pi;
92
SECURITY_ATTRIBUTES sa;
96
HANDLE hProcess, h, pipeThreads[2];
99
hProcess = GetCurrentProcess();
101
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
102
ZeroMemory(&si, sizeof(STARTUPINFO));
103
si.cb = sizeof(STARTUPINFO);
104
si.dwFlags = STARTF_USESTDHANDLES;
105
si.hStdInput = INVALID_HANDLE_VALUE;
107
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
108
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
109
sa.lpSecurityDescriptor = NULL;
110
sa.bInheritHandle = FALSE;
112
/* create a non-inheritible pipe. */
113
CreatePipe(&Out.pipe, &h, &sa, 0);
115
/* dupe the write side, make it inheritible, and close the original. */
116
DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput,
117
0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
119
/* Same as above, but for the error side. */
120
CreatePipe(&Err.pipe, &h, &sa, 0);
121
DuplicateHandle(hProcess, h, hProcess, &si.hStdError,
122
0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
124
/* base command line */
125
strcpy(cmdline, "cl.exe -nologo -c -TC -Fdtemp ");
126
/* append our option for testing */
127
strcat(cmdline, option);
128
/* filename to compile, which exists, but is nothing and empty. */
129
strcat(cmdline, " nul");
132
NULL, /* Module name. */
133
cmdline, /* Command line. */
134
NULL, /* Process handle not inheritable. */
135
NULL, /* Thread handle not inheritable. */
136
TRUE, /* yes, inherit handles. */
137
DETACHED_PROCESS, /* No console for you. */
138
NULL, /* Use parent's environment block. */
139
NULL, /* Use parent's starting directory. */
140
&si, /* Pointer to STARTUPINFO structure. */
141
&pi); /* Pointer to PROCESS_INFORMATION structure. */
144
DWORD err = GetLastError();
145
int chars = wsprintf(msg, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
147
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
148
FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID) &msg[chars],
150
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, strlen(msg), &err, NULL);
154
/* close our references to the write handles that have now been inherited. */
155
CloseHandle(si.hStdOutput);
156
CloseHandle(si.hStdError);
158
WaitForInputIdle(pi.hProcess, 5000);
159
CloseHandle(pi.hThread);
161
/* start the pipe reader threads. */
162
pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
163
pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
165
/* block waiting for the process to end. */
166
WaitForSingleObject(pi.hProcess, INFINITE);
167
CloseHandle(pi.hProcess);
169
/* clean up temporary files before returning */
170
DeleteFile("temp.idb");
171
DeleteFile("temp.pdb");
173
/* wait for our pipe to get done reading, should it be a little slow. */
174
WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
175
CloseHandle(pipeThreads[0]);
176
CloseHandle(pipeThreads[1]);
178
/* look for the commandline warning code in both streams. */
179
return !(strstr(Out.buffer, "D4002") != NULL || strstr(Err.buffer, "D4002") != NULL);
183
CheckForLinkerFeature (const char *option)
186
PROCESS_INFORMATION pi;
187
SECURITY_ATTRIBUTES sa;
191
HANDLE hProcess, h, pipeThreads[2];
194
hProcess = GetCurrentProcess();
196
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
197
ZeroMemory(&si, sizeof(STARTUPINFO));
198
si.cb = sizeof(STARTUPINFO);
199
si.dwFlags = STARTF_USESTDHANDLES;
200
si.hStdInput = INVALID_HANDLE_VALUE;
202
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
203
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
204
sa.lpSecurityDescriptor = NULL;
205
sa.bInheritHandle = TRUE;
207
/* create a non-inheritible pipe. */
208
CreatePipe(&Out.pipe, &h, &sa, 0);
210
/* dupe the write side, make it inheritible, and close the original. */
211
DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput,
212
0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
214
/* Same as above, but for the error side. */
215
CreatePipe(&Err.pipe, &h, &sa, 0);
216
DuplicateHandle(hProcess, h, hProcess, &si.hStdError,
217
0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
219
/* base command line */
220
strcpy(cmdline, "link.exe -nologo ");
221
/* append our option for testing */
222
strcat(cmdline, option);
223
/* filename to compile, which exists, but is nothing and empty. */
224
// strcat(cmdline, " nul");
227
NULL, /* Module name. */
228
cmdline, /* Command line. */
229
NULL, /* Process handle not inheritable. */
230
NULL, /* Thread handle not inheritable. */
231
TRUE, /* yes, inherit handles. */
232
DETACHED_PROCESS, /* No console for you. */
233
NULL, /* Use parent's environment block. */
234
NULL, /* Use parent's starting directory. */
235
&si, /* Pointer to STARTUPINFO structure. */
236
&pi); /* Pointer to PROCESS_INFORMATION structure. */
239
DWORD err = GetLastError();
240
int chars = wsprintf(msg, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
242
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
243
FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID) &msg[chars],
245
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, strlen(msg), &err, NULL);
249
/* close our references to the write handles that have now been inherited. */
250
CloseHandle(si.hStdOutput);
251
CloseHandle(si.hStdError);
253
WaitForInputIdle(pi.hProcess, 5000);
254
CloseHandle(pi.hThread);
256
/* start the pipe reader threads. */
257
pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
258
pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
260
/* block waiting for the process to end. */
261
WaitForSingleObject(pi.hProcess, INFINITE);
262
CloseHandle(pi.hProcess);
264
/* wait for our pipe to get done reading, should it be a little slow. */
265
WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
266
CloseHandle(pipeThreads[0]);
267
CloseHandle(pipeThreads[1]);
269
/* look for the commandline warning code in the stderr stream. */
270
return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL);
274
ReadFromPipe (LPVOID args)
276
pipeinfo *pi = (pipeinfo *) args;
277
char *lastBuf = pi->buffer;
282
ok = ReadFile(pi->pipe, lastBuf, 25, &dwRead, 0L);
283
if (!ok || dwRead == 0) {
284
CloseHandle(pi->pipe);
290
return 0; /* makes the compiler happy */
294
IsIn (const char *string, const char *substring)
296
return (strstr(string, substring) != NULL);