[ccache] direct mode design bug
ams at codesourcery.com
Thu Nov 8 07:04:28 MST 2012
On 07/11/12 19:19, Joel Rosdahl wrote:
> It would be nice if ccache were only used and enabled by conscious users
> who have read and understood the documentation, but in reality that
> doesn't happen in many cases. For instance, Linux distributions like
> Fedora install and enable ccache by default (masquerading the system
> compiler), at least when installing the development environment or
> similar. That's not surprising given that ccache works very well for
> most people and that it is advertised as being very safe.
Hmm, I was not aware Fedora did that, but then I don't use Fedora much,
and when I have Ccache is transparent enough I wouldn't necessarily
I am aware that Yocto uses it, by default, and certainly their users
could stumble of this problem, but again, only rarely.
> A similar issue, albeit not so interesting, perhaps, is what happens
> when a user changes some part of the toolchain, but does not alter
> the "gcc" binary. Ccache won't notice a new back-end compiler, a new
> assembler, a new linker, a new default specs file or anything like
> that. Chances are that any differences in the output are harmless,
> but the cached objects are technically invalid.
> Right. However, isn't the the fact that ccache may be affected by
> toolchain changes much less surprising than the fact that ccache may
> fail to pick up header files correctly?
That's why it's less interesting.
> [In fact, I have a use-case in which I have multiple users sharing a
> cache, and I wanted to be able to uniquely identify the same
> toolchain across all the installations. The mtime etc. varies from
> machine to machine, as might the exact tool mix, so I have some
> local patches to do a much deeper hash of the toolchain binaries,
> and include those in the object hashes. Even then, in the interests
> of performance, those toolchain IDs are cached according to the
> location and mtime, so changing the binutils will cause temporarily
> wrong toolchain hashes. Would you be interested in such a feature
> Perhaps, it depends on how intrusive it is and how toolchain-specific it is.
Basically, it first does the same as CCACHE_COMPILERCHECK=mtime, and
uses that to look for a <hash>.toolid file in the cache. If the tool-id
is cached it reads it from that file, and uses that ID to calculate the
opject hashes as usual. If the tool-id is not cached then it runs "gcc
-print-prog-name=..." a few times, hashes the binaries it finds, and
caches the result for next time. CCACHE_COMPILERCHECK=content causes the
ID to be re-cached, and =none and =<command> are unaltered.
By this means the cached files can be shared across machines with
toolchains that really are the same (all the way to the bottom) but
happen to have different installation times being recognised as the
same, and hashed as the same, but without having to re-hash the binary
An interesting side-effect is that binaries cached in
CCACHE_COMPILERCHECK=mtime mode are now compatible with those cached in
CCACHE_COMPILERCHECK=content mode, although those cached in the other
modes remain incompatible.
My implementation is currently GCC specific.
> Not sure about that. I maybe overlook something, but ccache would "only"
> have to follow all #include statements and note all header files that
> don't exist in the include path list. (When #include is used with a
> #defined token for the filename, fall back to the real compiler.) When
> considering a potential cache hit, reject it if any of the header files
> that didn't exist then exist now.
I was thinking of cases like:
Presumably you mean that it will note all the *directories* in which a
particular header file was not found, on the way to finding it?
> Anybody got other ideas?
> Running the compiler with -v prints the header search directories.
> You could use that to do your own scan.
> To use the directories from "cpp -v" (plus directories from the command
> line) to do some optimistic validation was my first thought as well, but
> after thinking more about it I came to the conclusion that it wouldn't
> buy much safety because no subdirectories will be checked, and you can't
> tell which subdirectories to check unless you have parsed the #include
> statements. Also, it would trigger many false negatives.
Yes, false negatives would happen, especially if there are include
directories within the project source tree. :(
The problem is that I've not been able to think of a way that both
solves your bug, and doesn't have a serious time-impact on either a
direct-mode lookup, or a cache-miss.
As it happens, I've been thinking of ways to speed up adding things into
the cache. I've been profiling the code, and found that, on a
cache-miss, it spends an significant portion of it's runtime between the
compiler exiting and ccache exiting. It has occurred to me that if we
were to return the compiler's results to the user straight away, it
could then fork into the background and spend as much time as it likes
populating the cache, without slowing the build time noticeably.
Compilations of the exact same source are unlikely to occur close
together, so there's no urgent deadline for these.
Given relaxed time constraints, we could certainly do a little more work
calculating data to store in the manifest file that could then be
processed lightening fast on a cache lookup.
So, for each include file, we need to know the list of directories it
could be found in, and which one it was actually found in. This means we
need to know what names were used in the original code (a user may have
specified an absolute path), whether they were included with <xxx.h> or
"xxx.h", and what directories were in the compiler's search path, and be
aware of #include_next directives.
Knowing the compiler's search path could be done with '-v' every time,
or we could cache the default ones, and then "know" what the
command-line parameters mean, or we could cache the search path for each
set of input options each time.
[Do all the supported toolchains even provide a means to learn the
search path? If we're getting into ptrace territory then architecture/OS
specific code will be required.]
Then, at direct-mode cache-lookup time, we do exactly as now, but also
have a list of locations where stat should return ENOENT.
> BTW, gcc has an option "--trace-includes" that might be faster than
> scanning the preprocessor output, although the compiler still has to
> do all the same work. Like this: "gcc -E hello.c -o /dev/null".
> How do you use --trace-includes? It doesn't seem to be documented and
> nothing happens when I try it.
Maybe it was introduced recently?
$ gcc --trace-includes -c ~/hello.c -o /dev/null
Multiple include guards may be useful for:
$ gcc --version
gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
Copyright © 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
More information about the ccache