Using ccache with clang 5 causes different results from just clang5

4

So with this contrived bit of code - compiling with clang works just fine, but when ccache is used extra warnings/errors appear - I thought ccache is supposed to transparently pass these through. This is ccache 3.1.6 on CentOS 6 from epel repo - upgrading is not an option as this is production environment.

#include <byteswap.h>

int main()
{
    int i = 42;
    auto j = bswap_32(i);
    (void)j;

    return 0;
}

So example 1 with unused include path gives no errors:

clang++ -Wno-c++98-compat -Wall -Werror -std=c++17 -I/usr/local/include -c ccache.cpp

But with ccache I get:

ccache clang++ -Wno-c++98-compat -Wall -Werror -std=c++17 -I/usr/include/xmlib -c ccache.cpp 
clang-5.0: error: argument unused during compilation: '-I /usr/include/xmlib' [-Werror,-Wunused-command-line-argument]

Example 2 without the extra include works just fine:

clang++ -Wno-c++98-compat -Wall -Werror -std=c++17  -c ccache.cpp

And with ccache

cache clang++ -Wno-c++98-compat -Wall -Werror -std=c++17  -c ccache.cpp 
ccache.cpp:6:32: error: ISO C++17 does not allow 'register' storage class specifier [-Wregister]
    auto j = (__extension__ ({ register unsigned int __v, __x = (i); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v; }));
                               ^~~~~~~~~
ccache.cpp:6:32: error: ISO C++17 does not allow 'register' storage class specifier [-Wregister]
    auto j = (__extension__ ({ register unsigned int __v, __x = (i); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v; }));
                                   ^~~~~~~~~
    2 errors generated.

Why does using ccache change the results?

clang++
ccache
asked on Stack Overflow Apr 19, 2018 by Adrian Cornish

1 Answer

6

The basic problem is that by default, ccache will pre-process the file (run the C-preprocessor on it) to get a single pre-processed translation unit which it uses to check its cache. Then, for efficiency's sake, if it "misses" in its cache and has to compile the file, it passes the pre-processed file directly to clang, telling clang not to run the pre-processor, only the compiler (e.g., by giving it the extension .i).

Since it is not running the pre-processor, -I arguments are inherently ignored, and this is what clang is complaining about. gcc is not as picky about this so it doesn't pose a problem there.

In ccache 3.2, fixes have been made and this problem goes away based on my local testing.

If you're stuck on 3.1, you can export CCACHE_CPP2=yes in your environment, which tells ccache to not bother with the above optimization and just pass the original C or C++ file into clang. How much performance this costs depends on the cost of pre-processing versus compilation.

I experienced this issue on TravisCI (which has an old 3.1 version of ccache) and this fixed it for me.

Your compilation error is probably rooted in the same reason: clang probably ignores errors in some or all system headers like <byteswap.h> but not in "user code". Since ccache passes it a big pre-processd blob, it all looks like user-code to clang.

This three part blog series explains this issue in more detail and contains links to relevant ccache bugs and discussion.

answered on Stack Overflow Aug 23, 2018 by BeeOnRope

User contributions licensed under CC BY-SA 3.0