#undef HAVE_MKSTEMP
#endif
-#define PATH_DELIM ":"
+#ifdef _WIN32
+int win32execute(char *path, char **argv, int doreturn,
+ const char *path_stdout, const char *path_stderr);
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0501
+# endif
+# include <windows.h>
+# define mkdir(a,b) mkdir(a)
+# define link(src,dst) (CreateHardLink(dst,src,NULL) ? 0 : -1)
+# define lstat(a,b) stat(a,b)
+# define execv(a,b) win32execute(a,b,0,NULL,NULL)
+# define execute(a,b,c) win32execute(*(a),a,1,b,c)
+# define PATH_DELIM ";"
+# define F_RDLCK 0
+# define F_WRLCK 0
+#else
+# define PATH_DELIM ":"
+#endif
#endif /* ifndef CCACHE_H */
static char *
find_executable_in_path(const char *name, const char *exclude_name, char *path);
+#ifdef _WIN32
+/*
+ * Re-create a win32 command line string based on **argv.
+ * http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+ */
+static char *argvtos(char *prefix, char **argv)
+{
+ char *arg;
+ char *ptr;
+ char *str;
+ int l = 0;
+ int i, j;
+
+ i = 0;
+ arg = prefix ? prefix : argv[i++];
+ do {
+ int bs = 0;
+ for (j = 0; arg[j]; j++) {
+ switch (arg[j]) {
+ case '\\':
+ bs++;
+ break;
+ case '"':
+ bs = (bs << 1) + 1;
+ default:
+ l += bs + 1;
+ bs = 0;
+ }
+ }
+ l += (bs << 1) + 3;
+ } while ((arg = argv[i++]));
+
+ str = ptr = malloc(l + 1);
+ if (str == NULL)
+ return NULL;
+
+ i = 0;
+ arg = prefix ? prefix : argv[i++];
+ do {
+ int bs = 0;
+ *ptr++ = '"';
+ for (j = 0; arg[j]; j++) {
+ switch (arg[j]) {
+ case '\\':
+ bs++;
+ break;
+ case '"':
+ bs = (bs << 1) + 1;
+ default:
+ while (bs && bs--)
+ *ptr++ = '\\';
+ *ptr++ = arg[j];
+ }
+ }
+ bs <<= 1;
+ while (bs && bs--)
+ *ptr++ = '\\';
+ *ptr++ = '"';
+ *ptr++ = ' ';
+ } while ((arg = argv[i++]));
+ ptr[-1] = '\0';
+
+ return str;
+}
+
+int win32execute(char *path, char **argv, int doreturn,
+ const char *path_stdout, const char *path_stderr)
+{
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ BOOL ret;
+ DWORD exitcode;
+ char *path_env;
+ char *sh = NULL;
+ char *args;
+ const char *ext;
+
+ memset(&pi, 0x00, sizeof(pi));
+ memset(&si, 0x00, sizeof(si));
+
+ ext = get_extension(path);
+ if (ext && !strcasecmp(ext, ".sh") && (path_env = getenv("PATH")))
+ sh = find_executable_in_path("sh.exe", NULL, path_env);
+ if (!sh && getenv("CCACHE_DETECT_SHEBANG")) {
+ /* Detect shebang. */
+ FILE *fp;
+ fp = fopen(path, "r");
+ if (fp) {
+ char buf[10];
+ fgets(buf, sizeof(buf), fp);
+ buf[9] = 0;
+ if (!strcmp(buf, "#!/bin/sh") && (path_env = getenv("PATH")))
+ sh = find_executable_in_path("sh.exe", NULL, path_env);
+ fclose(fp);
+ }
+ }
+ if (sh)
+ path = sh;
+
+ si.cb = sizeof(STARTUPINFO);
+ if (path_stdout) {
+ SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+ si.hStdOutput = CreateFile(path_stdout, GENERIC_WRITE, 0, &sa,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY |
+ FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ si.hStdError = CreateFile(path_stderr, GENERIC_WRITE, 0, &sa,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY |
+ FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ if (si.hStdOutput == INVALID_HANDLE_VALUE ||
+ si.hStdError == INVALID_HANDLE_VALUE)
+ return -1;
+ }
+ args = argvtos(sh, argv);
+ ret = CreateProcess(path, args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
+ free(args);
+ if (path_stdout) {
+ CloseHandle(si.hStdOutput);
+ CloseHandle(si.hStdError);
+ }
+ if (ret == 0)
+ return -1;
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ GetExitCodeProcess(pi.hProcess, &exitcode);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ if (!doreturn)
+ exit(exitcode);
+ return exitcode;
+}
+
+#else
+
/*
execute a compiler backend, capturing all output to the given paths
the full path to the compiler to run is in argv[0]
return WEXITSTATUS(status);
}
+#endif
/*
/* search the path looking for the first compiler of the right name
that isn't us */
for (tok=strtok(path, PATH_DELIM); tok; tok = strtok(NULL, PATH_DELIM)) {
+#ifdef _WIN32
+ char namebuf[MAX_PATH];
+ int ret = SearchPath(tok, name, ".exe",
+ sizeof(namebuf), namebuf, NULL);
+ if (!ret)
+ ret = SearchPath(tok, name, NULL,
+ sizeof(namebuf), namebuf, NULL);
+ (void) exclude_name;
+ if (ret) {
+ free(path);
+ return x_strdup(namebuf);
+ }
+#else
struct stat st1, st2;
char *fname;
x_asprintf(&fname, "%s/%s", tok, name);
return fname;
}
free(fname);
+#endif
}
free(path);
intermediate filename extensions used in this optimisation, in which case
this option could allow ccache to be used anyway.
+*CCACHE_DETECT_SHEBANG*::
+ The *CCACHE_DETECT_SHEBANG* environment variable only has meaning on
+ Windows. It instructs ccache to open the executable file to detect the
+ *#!/bin/sh* string, in which case ccache will search for *sh.exe* in
+ *PATH* and use that to launch the executable.
+
*CCACHE_DIR*::
The *CCACHE_DIR* environment variable specifies where ccache will keep its
host_os="`uname -s`"
case $host_os in
*MINGW*|*mingw*)
+ export CCACHE_DETECT_SHEBANG
+ CCACHE_DETECT_SHEBANG=1
DEVNULL=NUL
PATH_DELIM=";"
;;
#include <sys/time.h>
#endif
+#ifdef _WIN32
+#include <windows.h>
+#include <sys/locking.h>
+#endif
+
static FILE *logfile;
static int init_log(void)
char buf[10240];
int n, ret;
char *tmp_name;
+#ifndef _WIN32
mode_t mask;
+#endif
struct stat st;
int errnum;
gz_out = NULL;
}
+#ifndef _WIN32
/* get perms right on the tmp file */
mask = umask(0);
fchmod(fd_out, 0666 & ~mask);
umask(mask);
+#endif
/* the close can fail on NFS if out of space */
if (close(fd_out) == -1) {
char *p;
p = strrchr(s, '/');
if (p) s = p + 1;
+#ifdef _WIN32
+ p = strrchr(s, '\\');
+ if (p) s = p + 1;
+#endif
return x_strdup(s);
}
char *dirname(char *s)
{
char *p;
+ char *p2 = NULL;
s = x_strdup(s);
p = strrchr(s, '/');
+#ifdef _WIN32
+ p2 = strrchr(s, '\\');
+#endif
+ if (p < p2)
+ p = p2;
if (p) {
*p = 0;
return s;
static int lock_fd(int fd, short type)
{
+#ifdef _WIN32
+ (void) type;
+ return _locking(fd, _LK_NBLCK, 1);
+#else
struct flock fl;
int ret;
ret = fcntl(fd, F_SETLKW, &fl);
} while (ret == -1 && errno == EINTR);
return ret;
+#endif
}
int read_lock_fd(int fd)
/* return size on disk of a file */
size_t file_size(struct stat *st)
{
+#ifdef _WIN32
+ return (st->st_size + 1023) & ~1023;
+#else
size_t size = st->st_blocks * 512;
if ((size_t)st->st_size > size) {
/* probably a broken stat() call ... */
size = (st->st_size + 1023) & ~1023;
}
return size;
+#endif
}
}
+#ifndef _WIN32
/*
a sane realpath() function, trying to cope with stupid path limits and
a broken API
free(ret);
return NULL;
}
+#endif /* !_WIN32 */
/* a getcwd that will returns an allocated buffer */
char *gnu_getcwd(void)
int
compare_executable_name(const char *s1, const char *s2)
{
+#ifdef _WIN32
+ int ret = !strcasecmp(s1, s2);
+ if (!ret) {
+ char *tmp;
+ x_asprintf(&tmp, "%s.exe", s2);
+ ret = !strcasecmp(s1, tmp);
+ free(tmp);
+ }
+ return ret;
+#else
return !strcmp(s1, s2);
+#endif
}
/*
int
is_absolute_path(const char *path)
{
+#ifdef _WIN32
+ return path[0] && path[1] == ':';
+#else
return path[0] == '/';
+#endif
}
/*
{
if (strchr(path, '/'))
return 1;
+#ifdef _WIN32
+ if (strchr(path, '\\'))
+ return 1;
+#endif
return 0;
}
struct stat st;
void *data = (void *) -1;
int fd = -1;
+#ifdef _WIN32
+ HANDLE section;
+ HANDLE file;
+ file = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, 0, NULL);
+ if (file == INVALID_HANDLE_VALUE) {
+ cc_log("Failed to open %s%s", errstr, fname);
+ goto error;
+ }
+ fd = _open_osfhandle((intptr_t) file, O_RDONLY | O_BINARY);
+ if (fd == -1) {
+ cc_log("Failed to open %s%s", errstr, fname);
+ CloseHandle(file);
+ goto error;
+ }
+ if (fstat(fd, &st) == -1) {
+ cc_log("Failed to fstat %s%s", errstr, fname);
+ CloseHandle(file);
+ goto error;
+ }
+ section = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
+ CloseHandle(file);
+ if (!section) {
+ cc_log("Failed to mmap %s%s", errstr, fname);
+ goto error;
+ }
+ data = MapViewOfFile(section, FILE_MAP_READ, 0, 0, 0);
+ CloseHandle(section);
+#else
fd = open(fname, O_RDONLY | O_BINARY);
if (fd == -1) {
cc_log("Failed to open %s %s", errstr, fname);
if (data == (void *) -1) {
cc_log("Failed to mmap %s %s", errstr, fname);
}
+#endif
*size = st.st_size;
error:
return data;
*/
int x_munmap(void *addr, size_t length)
{
+#ifdef _WIN32
+ (void) length;
+ return UnmapViewOfFile(addr) ? 0 : -1;
+#else
return munmap(addr, length);
+#endif
}