diff options
author | Shawn Landden <slandden@gmail.com> | 2017-12-02 10:29:43 -0800 |
---|---|---|
committer | Shawn Landden <slandden@gmail.com> | 2018-02-25 22:08:49 -0800 |
commit | f2c978714cab690c2a41580095c72f058c2e53da (patch) | |
tree | 372d7bab997493ad2ceac8559a5b069cb8ea237d | |
parent | 2b160f3d20bc235c02c3b3da89d02a52509768e8 (diff) | |
download | distcc-git-f2c978714cab690c2a41580095c72f058c2e53da.tar.gz |
Rewrite generic compilers ("cc", "c++") to clang or gcc
depending on what these symlinks point to
-rw-r--r-- | src/compile.c | 82 | ||||
-rw-r--r-- | src/util.c | 28 | ||||
-rw-r--r-- | src/util.h | 1 |
3 files changed, 111 insertions, 0 deletions
diff --git a/src/compile.c b/src/compile.c index f78faa2..96bed2c 100644 --- a/src/compile.c +++ b/src/compile.c @@ -25,6 +25,7 @@ #include <config.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -445,6 +446,86 @@ static int dcc_please_send_email_after_investigation( return dcc_note_discrepancy(discrepancy_filename); } +/* Re-write "cc" to directly call gcc or clang + */ +static void dcc_rewrite_generic_compiler(char **argv) +{ +#ifdef __APPLE__ /* FIXME */ + + assert(argv); + + return; +#else + char linkbuf[MAXPATHLEN + 1], *link = NULL, *t; + int ret, dir; + ssize_t ssz; + struct stat st; + bool cpp = false; + + assert(argv); + + if (strcmp(argv[0], "cc") == 0) + ; + else if (strcmp(argv[0], "c++") == 0) + cpp = true; + else + return; + + ret = dcc_which(cpp ? "c++" : "cc", &link); + if (ret < 0) + return; + t = strrchr(link, '/'); + if (!t) + return; + *t = '\0'; + dir = open(link, O_RDONLY); + if (dir < 0) + return; + *t = '/'; + ret = fstatat(dir, t + 1, &st, AT_SYMLINK_NOFOLLOW); + if (ret < 0) + return; + if ((st.st_mode & S_IFMT) != S_IFLNK) + /* TODO use cc -v */ + return; + ssz = readlinkat(dir, t + 1, linkbuf, sizeof(linkbuf) - 1); + if (ssz < 0) + return; + linkbuf[ssz] = '\0'; + fstatat(dir, linkbuf, &st, AT_SYMLINK_NOFOLLOW); + if ((st.st_mode & S_IFMT) == S_IFLNK) { + /* this is a Debian thing. Fedora just has /usr/bin/cc -> gcc */ + if (strcmp(linkbuf, cpp ? "/etc/alternatives/c++" : "/etc/alternatives/cc") == 0) { + ssz = readlinkat(dir, linkbuf, linkbuf, sizeof(linkbuf) - 1); + linkbuf[ssz] = '\0'; + } + } + ret = faccessat(dir, linkbuf, X_OK, 0); + if (ret < 0) + return; + + if ( cpp && strcmp(strrchr(linkbuf, '/') ? strrchr(linkbuf, '/') + 1 : linkbuf, "clang++") == 0) { + free(argv[0]); + argv[0] = strdup("clang++"); + rs_trace("Rewriting '%s' to '%s'", "c++", "clang++"); + } else if ( cpp && strcmp(strrchr(linkbuf, '/') ? strrchr(linkbuf, '/') + 1 : linkbuf, "g++") == 0) { + free(argv[0]); + argv[0] = strdup("g++"); + rs_trace("Rewriting '%s' to '%s'", "c++", "g++"); + } else if (!cpp && strcmp(strrchr(linkbuf, '/') ? strrchr(linkbuf, '/') + 1 : linkbuf, "clang") == 0) { + free(argv[0]); + argv[0] = strdup("clang"); + rs_trace("Rewriting '%s' to '%s'", "cc", "clang"); + } else if (!cpp && strcmp(strrchr(linkbuf, '/') ? strrchr(linkbuf, '/') + 1 : linkbuf, "gcc") == 0) { + free(argv[0]); + argv[0] = strdup("gcc"); + rs_trace("Rewriting '%s' to '%s'", "cc", "gcc"); + } else + return; +#endif +} + + /* Clang is a native cross-compiler, but needs to be told to what target it is * building. * TODO: actually probe clang with clang --version, instead of trusting @@ -608,6 +689,7 @@ dcc_build_somewhere(char *argv[], dcc_free_argv(argv); argv = new_argv; if (!getenv("DISTCC_NO_REWRITE_CROSS")) { + dcc_rewrite_generic_compiler(new_argv); /* does not work on Mac FIXME */ dcc_add_clang_target(new_argv); dcc_gcc_rewrite_fqn(new_argv); } @@ -574,6 +574,34 @@ int dcc_remove_if_exists(const char *fname) return 0; } +int dcc_which(const char *command, char **out) +{ + char *loc = NULL, *path, *t; + int ret; + + path = getenv("PATH"); + if (!path) + return -ENOENT; + do { + /* emulate strchrnul() */ + t = strchr(path, ':'); + if (!t) + t = path + strlen(path); + loc = realloc(loc, t - path + 1 + strlen(command) + 1); + if (!loc) + return -ENOMEM; + strncpy(loc, path, t - path); + loc[t - path] = '\0'; + strcat(loc, "/"); + strcat(loc, command); + ret = access(loc, X_OK); + if (ret < 0) + continue; + *out = loc; + return 0; + } while ((path = strchr(path, ':') + 1)); + return -ENOENT; +} /* Returns the number of processes in state D, the max non-cc/c++ RSS in kb and * the max RSS program's name */ @@ -49,6 +49,7 @@ int dcc_get_dns_domain(const char **domain_name); void dcc_get_proc_stats(int *num_D, int *max_RSS, char **max_RSS_name); void dcc_get_disk_io_stats(int *n_reads, int *n_writes); +int dcc_which(const char *cmd, char **out); int dcc_dup_part(const char **psrc, char **pdst, const char *sep); |