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
23 find_executable_in_path(const char *name, const char *exclude_name, char *path);
27 * Re-create a win32 command line string based on **argv.
28 * http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
31 argvtos(char *prefix, char **argv)
40 arg = prefix ? prefix : argv[i++];
43 for (j = 0; arg[j]; j++) {
56 } while ((arg = argv[i++]));
58 str = ptr = malloc(l + 1);
63 arg = prefix ? prefix : argv[i++];
67 for (j = 0; arg[j]; j++) {
85 } while ((arg = argv[i++]));
92 win32execute(char *path, char **argv, int doreturn,
93 const char *path_stdout, const char *path_stderr)
95 PROCESS_INFORMATION pi;
104 memset(&pi, 0x00, sizeof(pi));
105 memset(&si, 0x00, sizeof(si));
107 ext = get_extension(path);
108 if (ext && strcasecmp(ext, ".sh") == 0 && (path_env = getenv("PATH")))
109 sh = find_executable_in_path("sh.exe", NULL, path_env);
110 if (!sh && getenv("CCACHE_DETECT_SHEBANG")) {
111 /* Detect shebang. */
113 fp = fopen(path, "r");
116 fgets(buf, sizeof(buf), fp);
118 if (str_eq(buf, "#!/bin/sh") && (path_env = getenv("PATH")))
119 sh = find_executable_in_path("sh.exe", NULL, path_env);
126 si.cb = sizeof(STARTUPINFO);
128 SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
129 si.hStdOutput = CreateFile(path_stdout, GENERIC_WRITE, 0, &sa,
130 CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY |
131 FILE_FLAG_SEQUENTIAL_SCAN, NULL);
132 si.hStdError = CreateFile(path_stderr, GENERIC_WRITE, 0, &sa,
133 CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY |
134 FILE_FLAG_SEQUENTIAL_SCAN, NULL);
135 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
136 si.dwFlags = STARTF_USESTDHANDLES;
137 if (si.hStdOutput == INVALID_HANDLE_VALUE ||
138 si.hStdError == INVALID_HANDLE_VALUE)
141 args = argvtos(sh, argv);
142 ret = CreateProcess(path, args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
145 CloseHandle(si.hStdOutput);
146 CloseHandle(si.hStdError);
150 WaitForSingleObject(pi.hProcess, INFINITE);
151 GetExitCodeProcess(pi.hProcess, &exitcode);
152 CloseHandle(pi.hProcess);
153 CloseHandle(pi.hThread);
162 execute a compiler backend, capturing all output to the given paths
163 the full path to the compiler to run is in argv[0]
166 execute(char **argv, const char *path_stdout, const char *path_stderr)
171 cc_log_argv("Executing ", argv);
174 if (pid == -1) fatal("Failed to fork: %s", strerror(errno));
179 tmp_unlink(path_stdout);
180 fd = open(path_stdout, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
187 tmp_unlink(path_stderr);
188 fd = open(path_stderr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
195 exit(execv(argv[0], argv));
198 if (waitpid(pid, &status, 0) != pid) {
199 fatal("waitpid failed: %s", strerror(errno));
202 if (WEXITSTATUS(status) == 0 && WIFSIGNALED(status)) {
206 return WEXITSTATUS(status);
212 * Find an executable by name in $PATH. Exclude any that are links to
216 find_executable(const char *name, const char *exclude_name)
220 if (is_absolute_path(name)) {
221 return x_strdup(name);
224 path = getenv("CCACHE_PATH");
226 path = getenv("PATH");
229 cc_log("No PATH variable");
233 return find_executable_in_path(name, exclude_name, path);
237 find_executable_in_path(const char *name, const char *exclude_name, char *path)
239 char *tok, *saveptr = NULL;
241 path = x_strdup(path);
243 /* search the path looking for the first compiler of the right name
245 for (tok = strtok_r(path, PATH_DELIM, &saveptr);
247 tok = strtok_r(NULL, PATH_DELIM, &saveptr)) {
249 char namebuf[MAX_PATH];
250 int ret = SearchPath(tok, name, ".exe",
251 sizeof(namebuf), namebuf, NULL);
253 ret = SearchPath(tok, name, NULL,
254 sizeof(namebuf), namebuf, NULL);
258 return x_strdup(namebuf);
261 struct stat st1, st2;
262 char *fname = format("%s/%s", tok, name);
263 /* look for a normal executable file */
264 if (access(fname, X_OK) == 0 &&
265 lstat(fname, &st1) == 0 &&
266 stat(fname, &st2) == 0 &&
267 S_ISREG(st2.st_mode)) {
268 if (S_ISLNK(st1.st_mode)) {
269 char *buf = x_realpath(fname);
271 char *p = basename(buf);
272 if (str_eq(p, exclude_name)) {
273 /* It's a link to "ccache"! */
296 print_command(FILE *fp, char **argv)
299 for (i = 0; argv[i]; i++) {
300 fprintf(fp, "%s%s", (i == 0) ? "" : " ", argv[i]);
306 print_executed_command(FILE *fp, char **argv)
308 fprintf(fp, "%s: executing ", MYNAME);
309 print_command(fp, argv);