2 * Copyright (C) Andrew Tridgell 2002
3 * Copyright (C) Joel Rosdahl 2011
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 3 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 extern struct conf *conf;
25 find_executable_in_path(const char *name, const char *exclude_name, char *path);
29 * Re-create a win32 command line string based on **argv.
30 * http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
33 win32argvtos(char *prefix, char **argv)
42 arg = prefix ? prefix : argv[i++];
45 for (j = 0; arg[j]; j++) {
58 } while ((arg = argv[i++]));
60 str = ptr = malloc(l + 1);
65 arg = prefix ? prefix : argv[i++];
69 for (j = 0; arg[j]; j++) {
87 /* cppcheck-suppress unreadVariable */
88 } while ((arg = argv[i++]));
95 win32getshell(char *path)
101 ext = get_extension(path);
102 if (ext && strcasecmp(ext, ".sh") == 0 && (path_env = getenv("PATH")))
103 sh = find_executable_in_path("sh.exe", NULL, path_env);
104 if (!sh && getenv("CCACHE_DETECT_SHEBANG")) {
105 /* Detect shebang. */
107 fp = fopen(path, "r");
110 fgets(buf, sizeof(buf), fp);
112 if (str_eq(buf, "#!/bin/sh") && (path_env = getenv("PATH")))
113 sh = find_executable_in_path("sh.exe", NULL, path_env);
121 void add_exe_ext_if_no_to_fullpath(char *full_path_win_ext, size_t max_size,
122 const char *ext, const char *path) {
123 if (!ext || (!str_eq(".exe", ext)
124 && !str_eq(".bat", ext)
125 && !str_eq(".EXE", ext)
126 && !str_eq(".BAT", ext))) {
127 snprintf(full_path_win_ext, max_size, "%s.exe", path);
129 snprintf(full_path_win_ext, max_size, "%s", path);
134 win32execute(char *path, char **argv, int doreturn,
135 int fd_stdout, int fd_stderr)
137 PROCESS_INFORMATION pi;
144 memset(&pi, 0x00, sizeof(pi));
145 memset(&si, 0x00, sizeof(si));
147 sh = win32getshell(path);
151 si.cb = sizeof(STARTUPINFO);
152 if (fd_stdout != -1) {
153 si.hStdOutput = (HANDLE)_get_osfhandle(fd_stdout);
154 si.hStdError = (HANDLE)_get_osfhandle(fd_stderr);
155 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
156 si.dwFlags = STARTF_USESTDHANDLES;
157 if (si.hStdOutput == INVALID_HANDLE_VALUE
158 || si.hStdError == INVALID_HANDLE_VALUE) {
162 /* redirect subprocess stdout, stderr into current process */
163 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
164 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
165 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
166 si.dwFlags = STARTF_USESTDHANDLES;
167 if (si.hStdOutput == INVALID_HANDLE_VALUE
168 || si.hStdError == INVALID_HANDLE_VALUE) {
172 args = win32argvtos(sh, argv);
174 const char *ext = strrchr(path, '.');
175 char full_path_win_ext[MAX_PATH] = {0};
176 add_exe_ext_if_no_to_fullpath(full_path_win_ext, MAX_PATH, ext, path);
177 ret = CreateProcess(full_path_win_ext, args, NULL, NULL, 1, 0, NULL, NULL,
179 if (fd_stdout != -1) {
187 DWORD dw = GetLastError();
190 FORMAT_MESSAGE_ALLOCATE_BUFFER |
191 FORMAT_MESSAGE_FROM_SYSTEM |
192 FORMAT_MESSAGE_IGNORE_INSERTS,
193 NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,
197 (LPVOID) LocalAlloc(LMEM_ZEROINIT,
198 (lstrlen((LPCTSTR) lpMsgBuf)
199 + lstrlen((LPCTSTR) __FILE__) + 200)
201 _snprintf((LPTSTR) lpDisplayBuf,
202 LocalSize(lpDisplayBuf) / sizeof(TCHAR),
203 TEXT("%s failed with error %d: %s"), __FILE__, dw, lpMsgBuf);
205 cc_log("can't execute %s; OS returned error: %s",
206 full_path_win_ext, (char *)lpDisplayBuf);
209 LocalFree(lpDisplayBuf);
213 WaitForSingleObject(pi.hProcess, INFINITE);
214 GetExitCodeProcess(pi.hProcess, &exitcode);
215 CloseHandle(pi.hProcess);
216 CloseHandle(pi.hThread);
224 /* Execute a compiler backend, capturing all output to the given paths the full
225 * path to the compiler to run is in argv[0]. */
227 execute(char **argv, int fd_out, int fd_err, pid_t *pid)
231 cc_log_argv("Executing ", argv);
238 fatal("Failed to fork: %s", strerror(errno));
247 x_exit(execv(argv[0], argv));
253 if (waitpid(*pid, &status, 0) != *pid) {
254 fatal("waitpid failed: %s", strerror(errno));
261 if (WEXITSTATUS(status) == 0 && WIFSIGNALED(status)) {
265 return WEXITSTATUS(status);
271 * Find an executable by name in $PATH. Exclude any that are links to
275 find_executable(const char *name, const char *exclude_name)
279 if (is_absolute_path(name)) {
280 return x_strdup(name);
284 if (str_eq(path, "")) {
285 path = getenv("PATH");
288 cc_log("No PATH variable");
292 return find_executable_in_path(name, exclude_name, path);
296 find_executable_in_path(const char *name, const char *exclude_name, char *path)
298 char *tok, *saveptr = NULL;
300 path = x_strdup(path);
302 /* search the path looking for the first compiler of the right name
304 for (tok = strtok_r(path, PATH_DELIM, &saveptr);
306 tok = strtok_r(NULL, PATH_DELIM, &saveptr)) {
308 char namebuf[MAX_PATH];
309 int ret = SearchPath(tok, name, NULL,
310 sizeof(namebuf), namebuf, NULL);
312 char *exename = format("%s.exe", name);
313 ret = SearchPath(tok, exename, NULL,
314 sizeof(namebuf), namebuf, NULL);
320 return x_strdup(namebuf);
323 struct stat st1, st2;
324 char *fname = format("%s/%s", tok, name);
325 /* look for a normal executable file */
326 if (access(fname, X_OK) == 0 &&
327 lstat(fname, &st1) == 0 &&
328 stat(fname, &st2) == 0 &&
329 S_ISREG(st2.st_mode)) {
330 if (S_ISLNK(st1.st_mode)) {
331 char *buf = x_realpath(fname);
333 char *p = basename(buf);
334 if (str_eq(p, exclude_name)) {
335 /* It's a link to "ccache"! */
358 print_command(FILE *fp, char **argv)
361 for (i = 0; argv[i]; i++) {
362 fprintf(fp, "%s%s", (i == 0) ? "" : " ", argv[i]);