From: Ramiro Polla Date: Fri, 16 Jul 2010 19:56:43 +0000 (-0300) Subject: Win32 support X-Git-Tag: v3.1~167^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4d7b4810bd3b8b53832605927c100a5ba4a60fb1;p=thirdparty%2Fccache.git Win32 support --- diff --git a/ccache.h b/ccache.h index 92247326c..55f839334 100644 --- a/ccache.h +++ b/ccache.h @@ -195,6 +195,23 @@ typedef int (*COMPAR_FN_T)(const void *, const void *); #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 +# 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 */ diff --git a/execute.c b/execute.c index 0d689a30a..3a8b34afc 100644 --- a/execute.c +++ b/execute.c @@ -33,6 +33,140 @@ 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] @@ -81,6 +215,7 @@ int execute(char **argv, return WEXITSTATUS(status); } +#endif /* @@ -116,6 +251,19 @@ find_executable_in_path(const char *name, const char *exclude_name, char *path) /* 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); @@ -146,6 +294,7 @@ find_executable_in_path(const char *name, const char *exclude_name, char *path) return fname; } free(fname); +#endif } free(path); diff --git a/manual.txt b/manual.txt index a821a0eee..aa22c8085 100644 --- a/manual.txt +++ b/manual.txt @@ -218,6 +218,12 @@ are doing. 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 diff --git a/test.sh b/test.sh index 7abeeea0a..d07b95f2f 100755 --- a/test.sh +++ b/test.sh @@ -1560,6 +1560,8 @@ cleanup host_os="`uname -s`" case $host_os in *MINGW*|*mingw*) + export CCACHE_DETECT_SHEBANG + CCACHE_DETECT_SHEBANG=1 DEVNULL=NUL PATH_DELIM=";" ;; diff --git a/util.c b/util.c index de87746a3..61fb541be 100644 --- a/util.c +++ b/util.c @@ -44,6 +44,11 @@ #include #endif +#ifdef _WIN32 +#include +#include +#endif + static FILE *logfile; static int init_log(void) @@ -186,7 +191,9 @@ int copy_file(const char *src, const char *dest, int compress_dest) char buf[10240]; int n, ret; char *tmp_name; +#ifndef _WIN32 mode_t mask; +#endif struct stat st; int errnum; @@ -275,10 +282,12 @@ int copy_file(const char *src, const char *dest, int compress_dest) 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) { @@ -614,6 +623,10 @@ char *basename(const char *s) 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); } @@ -622,8 +635,14 @@ char *basename(const char *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; @@ -665,6 +684,10 @@ char *remove_extension(const char *path) static int lock_fd(int fd, short type) { +#ifdef _WIN32 + (void) type; + return _locking(fd, _LK_NBLCK, 1); +#else struct flock fl; int ret; @@ -680,6 +703,7 @@ static int lock_fd(int fd, short type) ret = fcntl(fd, F_SETLKW, &fl); } while (ret == -1 && errno == EINTR); return ret; +#endif } int read_lock_fd(int fd) @@ -695,12 +719,16 @@ int write_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 } @@ -758,6 +786,7 @@ size_t value_units(const char *s) } +#ifndef _WIN32 /* a sane realpath() function, trying to cope with stupid path limits and a broken API @@ -800,6 +829,7 @@ char *x_realpath(const char *path) free(ret); return NULL; } +#endif /* !_WIN32 */ /* a getcwd that will returns an allocated buffer */ char *gnu_getcwd(void) @@ -887,7 +917,18 @@ char *get_cwd(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 } /* @@ -956,7 +997,11 @@ char *get_relative_path(const char *from, const char *to) int is_absolute_path(const char *path) { +#ifdef _WIN32 + return path[0] && path[1] == ':'; +#else return path[0] == '/'; +#endif } /* @@ -967,6 +1012,10 @@ is_full_path(const char *path) { if (strchr(path, '/')) return 1; +#ifdef _WIN32 + if (strchr(path, '\\')) + return 1; +#endif return 0; } @@ -993,6 +1042,35 @@ void *x_fmmap(const char *fname, off_t *size, const char *errstr) 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); @@ -1008,6 +1086,7 @@ void *x_fmmap(const char *fname, off_t *size, const char *errstr) if (data == (void *) -1) { cc_log("Failed to mmap %s %s", errstr, fname); } +#endif *size = st.st_size; error: return data; @@ -1018,5 +1097,10 @@ error: */ int x_munmap(void *addr, size_t length) { +#ifdef _WIN32 + (void) length; + return UnmapViewOfFile(addr) ? 0 : -1; +#else return munmap(addr, length); +#endif }