clang-target-wrapper: Filter the output from "clang -v" on windows
Convert paths with backslashes to forward slashes. libtool tries to parse this output in order to find object files and libraries that always should be linked in, but libtool can't handle paths with backslashes (and quotes) which clang currently outputs. This is a quick and ugly workaround until clang can be made to output paths with forward slashes on windows, see https://reviews.llvm.org/D53066 for progress on that matter.
This commit is contained in:
1 parent
643d9c1645
commit
8002486c84
1 file changed
+125
@@ -53,6 +53,12 @@ typedef char TCHAR;
|
||||
#define EXECVP_CAST (char **)
|
||||
#endif
|
||||
|
||||
#ifdef _UNICODE
|
||||
#define TS "%ls"
|
||||
#else
|
||||
#define TS "%s"
|
||||
#endif
|
||||
|
||||
static TCHAR *escape(const TCHAR *str) {
|
||||
#ifdef _WIN32
|
||||
TCHAR *out = malloc((_tcslen(str) * 2 + 3) * sizeof(*out));
|
||||
@@ -105,6 +111,116 @@ static TCHAR *_tcsrchrs(const TCHAR *str, TCHAR char1, TCHAR char2) {
|
||||
return ptr1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static int filter_line = 0, last_char = '\n';
|
||||
static void filter_stderr(char *buf, int n) {
|
||||
// Filter the stderr output from "-v" to rewrite paths from backslash
|
||||
// to forward slash form. libtool parses the output of "-v" and can't
|
||||
// handle the backslash form of paths. A proper upstream solution has
|
||||
// been discussed at https://reviews.llvm.org/D53066 but hasn't been
|
||||
// finished yet.
|
||||
int out = 0;
|
||||
int last = last_char;
|
||||
for (int i = 0; i < n; i++) {
|
||||
TCHAR cur = buf[i];
|
||||
// All lines that contain command lines or paths currently start
|
||||
// with a space.
|
||||
if (last == '\n') {
|
||||
filter_line = cur == ' ';
|
||||
}
|
||||
if (filter_line) {
|
||||
if (cur == '"') {
|
||||
// Do nothing; skip the quotes. This assumes that after
|
||||
// converting backslashes to forward slashes, there's nothing
|
||||
// else (e.g. spaces) that needs quoting. libtool would
|
||||
// probably not handle that anyway, but this would break
|
||||
// a more capable caller which also parses the output of "-v".
|
||||
} else if (cur == '\\') {
|
||||
// Convert backslashes to forward slashes. Quoted backslashes
|
||||
// are doubled, so just output every other one. We don't really
|
||||
// keep track of whether we're in a quoted context though.
|
||||
if (last != '\\') {
|
||||
buf[out++] = '/';
|
||||
} else {
|
||||
// Last output char was a backslash converted into a
|
||||
// forward slash. Ignore this one, but handle the next
|
||||
// one in case there's more.
|
||||
last = ' ';
|
||||
}
|
||||
} else {
|
||||
buf[out++] = cur;
|
||||
}
|
||||
} else {
|
||||
buf[out++] = cur;
|
||||
}
|
||||
|
||||
last = cur;
|
||||
}
|
||||
last_char = last;
|
||||
fwrite(buf, 1, out, stderr);
|
||||
}
|
||||
|
||||
static int exec_filtered(const TCHAR **argv) {
|
||||
int len = 1;
|
||||
for (int i = 0; argv[i]; i++)
|
||||
len += _tcslen(argv[i]) + 1;
|
||||
TCHAR *cmdline = malloc(len * sizeof(*cmdline));
|
||||
int pos = 0;
|
||||
// On Windows, the arguments are already quoted and escaped properly.
|
||||
for (int i = 0; argv[i]; i++) {
|
||||
_tcscpy(&cmdline[pos], argv[i]);
|
||||
pos += _tcslen(argv[i]);
|
||||
cmdline[pos++] = ' ';
|
||||
}
|
||||
if (pos > 0)
|
||||
pos--;
|
||||
cmdline[pos] = '\0';
|
||||
|
||||
STARTUPINFO si = { 0 };
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
HANDLE pipe_read = NULL, pipe_write = NULL;
|
||||
SECURITY_ATTRIBUTES sa = { 0 };
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.bInheritHandle = TRUE;
|
||||
CreatePipe(&pipe_read, &pipe_write, &sa, 0);
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
si.hStdError = pipe_write;
|
||||
if (!CreateProcess(NULL, cmdline, NULL, NULL, /* bInheritHandles */ TRUE,
|
||||
0, NULL, NULL, &si, &pi)) {
|
||||
DWORD err = GetLastError();
|
||||
TCHAR *errbuf;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &errbuf, 0, NULL);
|
||||
_ftprintf(stderr, _T("Unable to execute: "TS": "TS"\n"), cmdline, errbuf);
|
||||
LocalFree(errbuf);
|
||||
CloseHandle(pipe_read);
|
||||
CloseHandle(pipe_write);
|
||||
free(cmdline);
|
||||
return 1;
|
||||
}
|
||||
|
||||
CloseHandle(pipe_write);
|
||||
char stderr_buf[8192];
|
||||
DWORD n;
|
||||
while (ReadFile(pipe_read, stderr_buf, sizeof(stderr_buf), &n, NULL))
|
||||
filter_stderr(stderr_buf, n);
|
||||
CloseHandle(pipe_read);
|
||||
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
DWORD exit_code = 1;
|
||||
GetExitCodeProcess(pi.hProcess, &exit_code);
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
free(cmdline);
|
||||
return exit_code;
|
||||
}
|
||||
#endif
|
||||
|
||||
int _tmain(int argc, TCHAR* argv[]) {
|
||||
const TCHAR *argv0 = argv[0];
|
||||
const TCHAR *sep = _tcsrchrs(argv0, '/', '\\');
|
||||
@@ -200,6 +316,15 @@ int _tmain(int argc, TCHAR* argv[]) {
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// If the command line contains the "-v" argument, filter the stderr
|
||||
// output to rewrite paths from backslash to forward slash form.
|
||||
// libtool parses the output of "-v" and can't handle the backslash
|
||||
// form of paths. A proper upstream solution has been discussed at
|
||||
// https://reviews.llvm.org/D53066 but hasn't been finished yet.
|
||||
for (int i = 1; i < argc; i++)
|
||||
if (!_tcscmp(argv[i], _T("-v")))
|
||||
return exec_filtered(exec_argv);
|
||||
|
||||
int ret = _tspawnvp(_P_WAIT, exec_argv[0], exec_argv);
|
||||
if (ret == -1) {
|
||||
_tperror(exec_argv[0]);
|
||||
|
||||
Reference in new issue
Block a user