It is common for developers in a shared environment to compile the same
code, but in a different location [e.g. their home] and furthermore, to
use absolute path-names in their includes flags.  This results in two
different outputs from the preprocessor, even though the same file is
included [just different path], making it impossible to share a cache.
CCACHE_UNIFY could be used to get rid of the comments from the
preprocessor, but the problem here is of different nature: we do not
wish to UNIFY, and have side-effects such as wrong line information, but
rather just use relative paths so that the output of two preprocesses is
the same.

I've added a new boolean, CCACHE_RELATIVE that will modify all the -I
flags to be relative directories from where ccache is called.  An
absolute pathname will be retained if the "common root" between the
working directory and the included path is "/".  For example, the
following command line:
/home/sorbo$ gcc -I/common/stuff -I/home/sorbo/includes
will be translated to:
/home/sorbo$ gcc -I/common/stuff -Iincludes

Please consider applying this patch or implementing similar
functionality.  This scenario is very common in many work places.  The
patch is against ccache v2.4.

This has discussed on this mailing list to some extent, but I am unable
to see attached patches from the web archive, so I had to code something
myself.  Also, I don't know what happened to the proposed patches, so I
just redid the work.  References:

1) Steve Bennet "[ccache] [PATCH] Better cache reuse across builds in
separate trees":
http://lists.samba.org/archive/ccache/2005q2/000167.html

2) Chris Swiedler "[ccache] ccache and -g"
http://lists.samba.org/archive/ccache/2006q1/000201.html

---

diff -rup ccache-2.4.orig/ccache.c ccache-2.4/ccache.c
--- ccache-2.4.orig/ccache.c    2004-09-13 11:38:30.000000000 +0100
+++ ccache-2.4/ccache.c 2007-06-18 15:10:05.000000000 +0100
@@ -615,6 +615,119 @@ static const char *check_extension(const
        return NULL;
 }
 
+/* Transform an incldue path to relative, so that we get more hits */
+static char *relative(char *path)
+{
+       static char result[PATH_MAX];
+       static char *cwd;
+       char *proot, *pp;
+       char *croot, *cp;
+       char *rp;
+
+       /* path is relative */
+       if (*path != '/')
+               return path;
+
+       rp = x_realpath(path);
+       if (!rp) {
+               /* we got two options:
+                  1) remove the -I.  gcc works with inexistent paths, but this
+                     will screw up our cache.
+
+                  2) Try our best, hoping that path is well formed and won't
+                     affect us.
+
+                  I do #2 for now, in order to keep compiler generality.  Else,
+                  return NULL.  I prefer #1 though.
+               */
+#if 1
+               rp = x_strdup(path);
+#else
+               return NULL;
+#endif
+       }
+
+       /* init */
+       if (!cwd)  {
+               char *x = gnu_getcwd();
+
+               cwd = x_realpath(x);
+               free(x);
+       }
+       result[0] = 0;
+
+       /* step 1 - find common root */
+       cp = croot = cwd;
+       pp = proot = rp;
+       while (*pp && *cp) {
+               if (*pp != *cp)
+                       break;
+       
+               if (*pp == '/') {
+                       proot = pp;
+                       croot = cp;
+               }
+               pp++; cp++;
+       }
+
+       /* common root is root - don't relativize */
+       if (croot == cwd) {
+               free(rp);
+               return path;
+       }
+
+       /* same dir */  
+       if (*pp == 0 && *cp == 0) {
+               strcpy(result, ".");
+               free(rp);
+               return result;
+       }
+
+       /* parent */
+       if (*pp == 0) {
+               int len = strlen(proot);
+
+               if (strncmp(proot, croot, len) == 0 && croot[len] == '/') {
+                       croot++;
+                       proot = NULL;
+               }
+       }
+
+       /* subdir */
+       if (*cp == 0) {
+               int len = strlen(croot);
+
+               if (strncmp(croot, proot, len) == 0 && proot[len] == '/') {
+                       croot = cp;
+                       proot += len;
+               }
+       }
+
+       /* step 2 - cd to common root */
+       while (*croot) {
+               if (*croot++ == '/') {
+                       if (strlen(result) + 4 > sizeof(result)) {
+                               cc_log("relative: bad len");
+                               failed();
+                       }
+                       strcat(result, "../");
+               }
+       }
+
+       /* step 3 - cd to child (if any) */
+       if (proot) {
+               proot++;
+               if (strlen(result) + strlen(proot) + 1 > sizeof(result)) {
+                       cc_log("relative: bad len2");
+                       failed();
+               }
+               strcat(result, proot);
+       }
+
+       free(rp);
+
+       return result;
+}
 
 /* 
    process the compiler options to form the correct set of options 
@@ -704,7 +817,7 @@ static void process_args(int argc, char 
 
                /* options that take an argument */
                {
-                       const char *opts[] = {"-I", "-include", "-imacros", 
"-iprefix",
+                       const char *opts[] = {"-include", "-imacros", 
"-iprefix",
                                              "-iwithprefix", 
"-iwithprefixbefore",
                                              "-L", "-D", "-U", "-x", "-MF", 
                                              "-MT", "-MQ", "-isystem", 
"-aux-info",
@@ -730,6 +843,32 @@ static void process_args(int argc, char 
                        if (opts[j]) continue;
                }
 
+               /* transform paths to relative so that builds in different trees
+                * hit
+                */
+               if (strncmp(argv[i], "-I", 2) == 0) {
+                       char *arg = &argv[i][2];
+
+                       /* see if arg is not glued */
+                       if (*arg == 0) {
+                               if (i == argc-1) {
+                                       cc_log("missing argument to -I\n");
+                                       stats_update(STATS_ARGS);
+                                       failed();
+                               }
+                               i++;
+                               arg = argv[i];
+                       }
+
+                       if (getenv("CCACHE_RELATIVE"))
+                               arg = relative(arg);
+                       if (!arg)
+                               continue;
+                       args_add(stripped_args, "-I");
+                       args_add(stripped_args, arg);
+                       continue;
+               }
+
                /* other options */
                if (argv[i][0] == '-') {
                        args_add(stripped_args, argv[i]);

Reply via email to