Thursday, September 15, 2011

ccache and clang, part 2

There's more funny business when using ccache in combination with clang. Last time I suggested that you use the invocation
./configure CC='ccache clang -Qunused-arguments -fcolor-diagnostics'
to get rid of the "argument unused during compilation" warnings.

But you still might get loads of warnings that you wouldn't normally get without ccache, such as this example (from the PostgreSQL source code):

extension.c:382:35: warning: equality comparison with extraneous parentheses [-Wparentheses]
 if (( (((control->directory)[0]) == '/') ))
extension.c:382:35: note: use '=' to turn this equality comparison into an assignment
(This is the opposite of the warning that tells you to put two pairs of parentheses around an assignment used as a truth value.) Or:
path.c:727:7: warning: explicitly assigning a variable of type 'char *' to itself [-Wself-assign]
 path = (path);
 ~~~~ ^  ~~~~
The problem is, these come from macro expansions, so wouldn't normally see them, because (I guess) the compiler driver is smart enough not to warn about such things when they come from macro expansions.

The way ccache works is approximately

  1. preprocess the input file
  2. look for it in the cache
  3. if not found, compile the preprocessed file
What would be better in this situation is
  1. preprocess the input file
  2. look for it in the cache
  3. if not found, compile the original file
And indeed you can turn on that second behavior by setting the obscure environment variable CCACHE_CPP2 (as in, run cpp twice):
export CCACHE_CPP2=yes
Then all these extra warnings disappear.

(The ccache man page is worth a read. There are a few interesting settings to play with.)

I'm currently playing around with a shell script ccache-clang that looks like this:

CCACHE_CPP2=yes exec ccache clang -Qunused-arguments `test -t 2 && echo -fcolor-diagnostics` "$@"


  1. ccache imo is just a poor man's solution to broken build systems (ie, those who can't track dependencies properly, so far only SCons don't fall into that category). The rest - includes makefile, aren't tracking dependencies properly, and you need to devise such redundant solutions like ccache.

  2. ccache avoids running cpp twice because doing so makes builds take longer when not hitting the cache.

  3. Sometimes it's better to set PATH=/usr/lib/ccache:$PATH instead of setting CC="ccache foo bar". Especially helped to build stuff using APR libraries properly.

    Not sure if it makes any difference in this case...

  4. @Greg: Yes, it's often a workaround, but not always. Say, I have several local Git branches and switch around between them. Every time I switch to a new branch, some things need to be rebuild. If I had already built this branch earlier, things would be in the cache.

  5. @jvtm: It sometimes helps if the makefiles are written in a broken way, but it doesn't make a difference for the matter discussed here.

  6. Hi Peter,

    when experimenting with the CPP2 workaround I noticed that the -Qunused-arguments parameter isn't needed anymore. All those warnings magically went away...


  7. Excellent information to have. Thanks for this and the first installment.

  8. Update: