summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Landden <slandden@gmail.com>2017-12-02 10:29:43 -0800
committerShawn Landden <slandden@gmail.com>2018-02-25 22:08:49 -0800
commitf2c978714cab690c2a41580095c72f058c2e53da (patch)
tree372d7bab997493ad2ceac8559a5b069cb8ea237d
parent2b160f3d20bc235c02c3b3da89d02a52509768e8 (diff)
downloaddistcc-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.c82
-rw-r--r--src/util.c28
-rw-r--r--src/util.h1
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);
}
diff --git a/src/util.c b/src/util.c
index 4b26fa7..c4939cd 100644
--- a/src/util.c
+++ b/src/util.c
@@ -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 */
diff --git a/src/util.h b/src/util.h
index 463a383..92017c5 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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);