Import ccache-2.4 source

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10900 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
William S Fulton 2008-11-03 13:37:28 +00:00
commit 482d91951a
27 changed files with 11335 additions and 0 deletions

8
CCache/.cvsignore Normal file
View file

@ -0,0 +1,8 @@
Makefile
ccache
*gz
config.h
config.log
config.status
tca.log
tca.map

339
CCache/COPYING Normal file
View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

53
CCache/Makefile.in Normal file
View file

@ -0,0 +1,53 @@
srcdir=@srcdir@
VPATH=@srcdir@
prefix=@prefix@
exec_prefix=@exec_prefix@
bindir=@bindir@
mandir=@mandir@
INSTALLCMD=@INSTALL@
CC=@CC@
CFLAGS=@CFLAGS@ -I.
EXEEXT=@EXEEXT@
OBJS= ccache.o mdfour.o hash.o execute.o util.o args.o stats.o \
cleanup.o snprintf.o unify.o
HEADERS = ccache.h mdfour.h
all: ccache$(EXEEXT)
docs: ccache.1 web/ccache-man.html
ccache$(EXEEXT): $(OBJS) $(HEADERS)
$(CC) $(CFLAGS) -o $@ $(OBJS)
ccache.1: ccache.yo
-yodl2man -o ccache.1 ccache.yo
web/ccache-man.html: ccache.yo
mkdir -p man
yodl2html -o web/ccache-man.html ccache.yo
install: ccache$(EXEEXT) ccache.1
${INSTALLCMD} -d $(DESTDIR)${bindir}
${INSTALLCMD} -m 755 ccache$(EXEEXT) $(DESTDIR)${bindir}
${INSTALLCMD} -d $(DESTDIR)${mandir}/man1
${INSTALLCMD} -m 644 ${srcdir}/ccache.1 $(DESTDIR)${mandir}/man1/
clean:
/bin/rm -f $(OBJS) *~ ccache$(EXEEXT)
test: test.sh
CC='$(CC)' ./test.sh
check: test
distclean: clean
/bin/rm -f Makefile config.h config.sub config.log build-stamp config.status
# FIXME: To fix this, test.sh needs to be able to take ccache from the
# installed prefix, not from the source dir.
installcheck:
@echo "WARNING! This is not really \"installcheck\" yet."
$(MAKE) check

31
CCache/README Normal file
View file

@ -0,0 +1,31 @@
This is a re-implementation of "compilercache" in C
The original compilercache scripts were by Erik Thiele
(erikyyy@erikyyy.de) and I would like to thank him for an excellent
piece of work. See http://www.erikyyy.de/compilercache/ for the
original shell scripts.
I wrote ccache because I wanted to get a bit more speed out of a
compiler cache and I wanted to remove some of the limitations of the
shell-script version.
Please see the manual page and documentation at
http://ccache.samba.org/
INSTALLATION
------------
Please run:
./configure
make
make install
then read the ccache manual page
-----------
Andrew Tridgell
http://samba.org/~tridge/
bugs@ccache.samba.org

91
CCache/args.c Normal file
View file

@ -0,0 +1,91 @@
/*
convenient routines for argument list handling
Copyright (C) Andrew Tridgell 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ccache.h"
ARGS *args_init(int init_argc, char **init_args)
{
ARGS *args;
int i;
args = (ARGS *)x_malloc(sizeof(ARGS));
args->argc = 0;
args->argv = (char **)x_malloc(sizeof(char *));
args->argv[0] = NULL;
for (i=0;i<init_argc;i++) {
args_add(args, init_args[i]);
}
return args;
}
void args_add(ARGS *args, const char *s)
{
args->argv = (char**)x_realloc(args->argv, (args->argc + 2) * sizeof(char *));
args->argv[args->argc] = x_strdup(s);
args->argc++;
args->argv[args->argc] = NULL;
}
/* pop the last element off the args list */
void args_pop(ARGS *args, int n)
{
while (n--) {
args->argc--;
free(args->argv[args->argc]);
args->argv[args->argc] = NULL;
}
}
/* remove the first element of the argument list */
void args_remove_first(ARGS *args)
{
free(args->argv[0]);
memmove(&args->argv[0],
&args->argv[1],
args->argc * sizeof(args->argv[0]));
args->argc--;
}
/* add an argument into the front of the argument list */
void args_add_prefix(ARGS *args, const char *s)
{
args->argv = (char**)x_realloc(args->argv, (args->argc + 2) * sizeof(char *));
memmove(&args->argv[1], &args->argv[0],
(args->argc+1) * sizeof(args->argv[0]));
args->argv[0] = x_strdup(s);
args->argc++;
}
/* strip any arguments beginning with the specified prefix */
void args_strip(ARGS *args, const char *prefix)
{
int i;
for (i=0; i<args->argc; ) {
if (strncmp(args->argv[i], prefix, strlen(prefix)) == 0) {
free(args->argv[i]);
memmove(&args->argv[i],
&args->argv[i+1],
args->argc * sizeof(args->argv[i]));
args->argc--;
} else {
i++;
}
}
}

396
CCache/ccache.1 Normal file
View file

@ -0,0 +1,396 @@
.TH "ccache" "1" "April 2002" "" ""
.SH "NAME"
ccache \- a fast compiler cache
.SH "SYNOPSIS"
.PP
ccache [OPTION]
.PP
ccache <compiler> [COMPILER OPTIONS]
.PP
<compiler> [COMPILER OPTIONS]
.PP
.SH "DESCRIPTION"
.PP
ccache is a compiler cache\&. It speeds up re-compilation of C/C++ code
by caching previous compiles and detecting when the same compile is
being done again\&.
.PP
.SH "OPTIONS SUMMARY"
.PP
Here is a summary of the options to ccache\&.
.PP
.nf
-s show statistics summary
-z zero statistics
-c run a cache cleanup
-C clear the cache completely
-F <maxfiles> set maximum files in cache
-M <maxsize> set maximum size of cache (use G, M or K)
-h this help page
-V print version number
.fi
.PP
.SH "OPTIONS"
.PP
These options only apply when you invoke ccache as "ccache"\&. When
invoked as a compiler none of these options apply\&. In that case your
normal compiler options apply and you should refer to your compilers
documentation\&.
.PP
.IP "\fB-h\fP"
Print a options summary page
.IP
.IP "\fB-s\fP"
Print the current statistics summary for the cache\&. The
statistics are stored spread across the subdirectories of the
cache\&. Using "ccache -s" adds up the statistics across all
subdirectories and prints the totals\&.
.IP
.IP "\fB-z\fP"
Zero the cache statistics\&.
.IP
.IP "\fB-V\fP"
Print the ccache version number
.IP
.IP "\fB-c\fP"
Clean the cache and re-calculate the cache file count and
size totals\&. Normally the -c option should not be necessary as ccache
keeps the cache below the specified limits at runtime and keeps
statistics up to date on each compile\&. This option is mostly useful
if you manually modify the cache contents or believe that the cache
size statistics may be inaccurate\&.
.IP
.IP "\fB-C\fP"
Clear the entire cache, removing all cached files\&.
.IP
.IP "\fB-F maxfiles\fP"
This sets the maximum number of files allowed in
the cache\&. The value is stored inside the cache directory and applies
to all future compiles\&. Due to the way the value is stored the actual
value used is always rounded down to the nearest multiple of 16\&.
.IP
.IP "\fB-M maxsize\fP"
This sets the maximum cache size\&. You can specify
a value in gigabytes, megabytes or kilobytes by appending a G, M or K
to the value\&. The default is gigabytes\&. The actual value stored is
rounded down to the nearest multiple of 16 kilobytes\&.
.IP
.PP
.SH "INSTALLATION"
.PP
There are two ways to use ccache\&. You can either prefix your compile
commands with "ccache" or you can create a symbolic link between
ccache and the names of your compilers\&. The first method is most
convenient if you just want to try out ccache or wish to use it for
some specific projects\&. The second method is most useful for when you
wish to use ccache for all your compiles\&.
.PP
To install for usage by the first method just copy ccache to somewhere
in your path\&.
.PP
To install for the second method do something like this:
.nf
cp ccache /usr/local/bin/
ln -s /usr/local/bin/ccache /usr/local/bin/gcc
ln -s /usr/local/bin/ccache /usr/local/bin/g++
ln -s /usr/local/bin/ccache /usr/local/bin/cc
.fi
This will work as long as /usr/local/bin comes before the path to gcc
(which is usually in /usr/bin)\&. After installing you may wish to run
"which gcc" to make sure that the correct link is being used\&.
.PP
Note! Do not use a hard link, use a symbolic link\&. A hardlink will
cause "interesting" problems\&.
.PP
.SH "EXTRA OPTIONS"
.PP
When run as a compiler front end ccache usually just takes the same
command line options as the compiler you are using\&. The only exception
to this is the option \&'--ccache-skip\&'\&. That option can be used to tell
ccache that the next option is definitely not a input filename, and
should be passed along to the compiler as-is\&.
.PP
The reason this can be important is that ccache does need to parse the
command line and determine what is an input filename and what is a
compiler option, as it needs the input filename to determine the name
of the resulting object file (among other things)\&. The heuristic
ccache uses in this parse is that any string on the command line that
exists as a file is treated as an input file name (usually a C
file)\&. By using --ccache-skip you can force an option to not be
treated as an input file name and instead be passed along to the
compiler as a command line option\&.
.PP
.SH "ENVIRONMENT VARIABLES"
.PP
ccache uses a number of environment variables to control operation\&. In
most cases you won\&'t need any of these as the defaults will be fine\&.
.PP
.IP
.IP "\fBCCACHE_DIR\fP"
the CCACHE_DIR environment variable specifies
where ccache will keep its cached compiler output\&. The default is
"$HOME/\&.ccache"\&.
.IP
.IP "\fBCCACHE_TEMPDIR\fP"
the CCACHE_TEMPDIR environment variable specifies
where ccache will put temporary files\&. The default is the same as
CCACHE_DIR\&. Note that the CCACHE_TEMPDIR path must be on the same
filesystem as the CCACHE_DIR path, so that renames of files between
the two directories can work\&.
.IP
.IP "\fBCCACHE_LOGFILE\fP"
If you set the CCACHE_LOGFILE environment
variable then ccache will write some log information on cache hits
and misses in that file\&. This is useful for tracking down problems\&.
.IP
.IP "\fBCCACHE_PATH\fP"
You can optionally set CCACHE_PATH to a colon
separated path where ccache will look for the real compilers\&. If you
don\&'t do this then ccache will look for the first executable matching
the compiler name in the normal PATH that isn\&'t a symbolic link to
ccache itself\&.
.IP
.IP "\fBCCACHE_CC\fP"
You can optionally set CCACHE_CC to force the name
of the compiler to use\&. If you don\&'t do this then ccache works it out
from the command line\&.
.IP
.IP "\fBCCACHE_PREFIX\fP"
This option adds a prefix to the command line
that ccache runs when invoking the compiler\&. Also see the section
below on using ccache with distcc\&.
.IP
.IP "\fBCCACHE_DISABLE\fP"
If you set the environment variable
CCACHE_DISABLE then ccache will just call the real compiler,
bypassing the cache completely\&.
.IP
.IP "\fBCCACHE_READONLY\fP"
the CCACHE_READONLY environment variable
tells ccache to attempt to use existing cached object files, but not
to try to add anything new to the cache\&. If you are using this because
your CCACHE_DIR is read-only, then you may find that you also need to
set CCACHE_TEMPDIR as otherwise ccache will fail to create the
temporary files\&.
.IP
.IP "\fBCCACHE_CPP2\fP"
If you set the environment variable CCACHE_CPP2
then ccache will not use the optimisation of avoiding the 2nd call to
the pre-processor by compiling the pre-processed output that was used
for finding the hash in the case of a cache miss\&. This is primarily a
debugging option, although it is possible that some unusual compilers
will have problems with the intermediate filename extensions used in
this optimisation, in which case this option could allow ccache to be
used\&.
.IP
.IP "\fBCCACHE_NOSTATS\fP"
If you set the environment variable
CCACHE_NOSTATS then ccache will not update the statistics files on
each compile\&.
.IP
.IP "\fBCCACHE_NLEVELS\fP"
The environment variable CCACHE_NLEVELS allows
you to choose the number of levels of hash in the cache directory\&. The
default is 2\&. The minimum is 1 and the maximum is 8\&.
.IP
.IP "\fBCCACHE_HARDLINK\fP"
If you set the environment variable
CCACHE_HARDLINK then ccache will attempt to use hard links from the
cache directory when creating the compiler output rather than using a
file copy\&. Using hard links is faster, but can confuse programs like
\&'make\&' that rely on modification times\&.
.IP
.IP "\fBCCACHE_RECACHE\fP"
This forces ccache to not use any cached
results, even if it finds them\&. New results are still cached, but
existing cache entries are ignored\&.
.IP
.IP "\fBCCACHE_UMASK\fP"
This sets the umask for ccache and all child
processes (such as the compiler)\&. This is mostly useful when you wish
to share your cache with other users\&. Note that this also affects the
file permissions set on the object files created from your
compilations\&.
.IP
.IP "\fBCCACHE_HASHDIR\fP"
This tells ccache to hash the current working
directory when calculating the hash that is used to distinguish two
compiles\&. This prevents a problem with the storage of the current
working directory in the debug info of a object file, which can lead
ccache to give a cached object file that has the working directory in
the debug info set incorrectly\&. This option is off by default as the
incorrect setting of this debug info rarely causes problems\&. If you
strike problems with gdb not using the correct directory then enable
this option\&.
.IP
.IP "\fBCCACHE_UNIFY\fP"
If you set the environment variable CCACHE_UNIFY
then ccache will use the C/C++ unifier when hashing the pre-processor
output if -g is not used in the compile\&. The unifier is slower than a
normal hash, so setting this environment variable loses a little bit
of speed, but it means that ccache can take advantage of not
recompiling when the changes to the source code consist of
reformatting only\&. Note that using CCACHE_UNIFY changes the hash, so
cached compiles with CCACHE_UNIFY set cannot be used when
CCACHE_UNIFY is not set and vice versa\&. The reason the unifier is off
by default is that it can give incorrect line number information in
compiler warning messages\&.
.IP
.IP "\fBCCACHE_EXTENSION\fP"
Normally ccache tries to automatically
determine the extension to use for intermediate C pre-processor files
based on the type of file being compiled\&. Unfortunately this sometimes
doesn\&'t work, for example when using the aCC compiler on HP-UX\&. On
systems like this you can use the CCACHE_EXTENSION option to override
the default\&. On HP-UX set this environment variable to "i" if you use
the aCC compiler\&.
.IP
.PP
.SH "CACHE SIZE MANAGEMENT"
.PP
By default ccache has a one gigabyte limit on the cache size and no
maximum number of files\&. You can set a different limit using the
"ccache -M" and "ccache -F" options, which set the size and number of
files limits\&.
.PP
When these limits are reached ccache will reduce the cache to 20%
below the numbers you specified in order to avoid doing the cache
clean operation too often\&.
.PP
.SH "HOW IT WORKS"
.PP
The basic idea is to detect when you are compiling exactly the same
code a 2nd time and use the previously compiled output\&. You detect
that it is the same code by forming a hash of:
.PP
.IP o
the pre-processor output from running the compiler with -E
.IP o
the command line options
.IP o
the real compilers size and modification time
.IP o
any stderr output generated by the compiler
.PP
These are hashed using md4 (a strong hash) and a cache file is formed
based on that hash result\&. When the same compilation is done a second
time ccache is able to supply the correct compiler output (including
all warnings etc) from the cache\&.
.PP
ccache has been carefully written to always produce exactly the same
compiler output that you would get without the cache\&. If you ever
discover a case where ccache changes the output of your compiler then
please let me know\&.
.PP
.SH "USING CCACHE WITH DISTCC"
.PP
distcc is a very useful program for distributing compilation across a
range of compiler servers\&. It is often useful to combine distcc with
ccache, so that compiles that are done are sped up by distcc, but that
ccache avoids the compile completely where possible\&.
.PP
To use distcc with ccache I recommend using the CCACHE_PREFIX
option\&. You just need to set the environment variable CCACHE_PREFIX to
\&'distcc\&' and ccache will prefix the command line used with the
compiler with the command \&'distcc\&'\&.
.PP
.SH "SHARING A CACHE"
.PP
A group of developers can increase the cache hit rate by sharing a
cache directory\&. The hard links however cause unwanted side effects,
as all links to a cached file share the file\&'s modification timestamp\&.
This results in false dependencies to be triggered by timestamp-based
build systems whenever another user links to an existing
file\&. Typically, users will see that their libraries and binaries are
relinked without reason\&. To share a cache without side effects, the
following conditions need to be met:
.PP
.IP o
Use the same \fBCCACHE_DIR\fP environment variable setting
.IP o
Set the \fBCCACHE_NOLINK\fP environment variable
.IP o
Make sure everyone sets the CCACHE_UMASK environment variable
to 002, this ensures that cached files are accessible to everyone in
the group\&.
.IP o
Make sure that all users have write permission in the entire
cache directory (and that you trust all users of the shared cache)\&.
.IP o
Make sure that the setgid bit is set on all directories in the
cache\&. This tells the filesystem to inherit group ownership for new
directories\&. The command "chmod g+s `find $CCACHE_DIR -type d`" might
be useful for this\&.
.PP
.SH "HISTORY"
.PP
ccache was inspired by the compilercache shell script script written
by Erik Thiele and I would like to thank him for an excellent piece of
work\&. See
http://www\&.erikyyy\&.de/compilercache/
for the Erik\&'s scripts\&.
.PP
I wrote ccache because I wanted to get a bit more speed out of a
compiler cache and I wanted to remove some of the limitations of the
shell-script version\&.
.PP
.SH "DIFFERENCES FROM COMPILERCACHE"
.PP
The biggest differences between Erik\&'s compilercache script and ccache
are:
.IP o
ccache is written in C, which makes it a bit faster (calling out to
external programs is mostly what slowed down the scripts)\&.
.IP o
ccache can automatically find the real compiler
.IP o
ccache keeps statistics on hits/misses
.IP o
ccache can do automatic cache management
.IP o
ccache can cache compiler output that includes warnings\&. In many
cases this gives ccache a much higher cache hit rate\&.
.IP o
ccache can handle a much wider ranger of compiler options
.IP o
ccache avoids a double call to cpp on a cache miss
.PP
.SH "BUGS"
.PP
When the cache is stored on an NFS filesystem, the filesystem must be
exported with the \fBno_subtree_check\fP option to make renames between
directories reliable\&.
.PP
.SH "CREDITS"
.PP
Thanks to the following people for their contributions to ccache
.IP o
Erik Thiele for the original compilercache script
.IP o
Luciano Rocha for the idea of compiling the pre-processor output
to avoid a 2nd cpp pass
.IP o
Paul Russell for many suggestions and the debian packaging
.PP
.SH "AUTHOR"
.PP
ccache was written by Andrew Tridgell
http://samba\&.org/~tridge/
.PP
If you wish to report a problem or make a suggestion then please email
bugs@ccache\&.samba\&.org
.PP
ccache is released under the GNU General Public License version 2 or
later\&. Please see the file COPYING for license details\&.

1034
CCache/ccache.c Normal file

File diff suppressed because it is too large Load diff

159
CCache/ccache.h Normal file
View file

@ -0,0 +1,159 @@
#define CCACHE_VERSION "2.4"
#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <utime.h>
#include <stdarg.h>
#include <dirent.h>
#include <limits.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#define STATUS_NOTFOUND 3
#define STATUS_FATAL 4
#define STATUS_NOCACHE 5
#define MYNAME "ccache"
#define LIMIT_MULTIPLE 0.8
/* default maximum cache size */
#ifndef DEFAULT_MAXSIZE
#define DEFAULT_MAXSIZE (1000*1000)
#endif
enum stats {
STATS_NONE=0,
STATS_STDOUT,
STATS_STATUS,
STATS_ERROR,
STATS_TOCACHE,
STATS_PREPROCESSOR,
STATS_COMPILER,
STATS_MISSING,
STATS_CACHED,
STATS_ARGS,
STATS_LINK,
STATS_NUMFILES,
STATS_TOTALSIZE,
STATS_MAXFILES,
STATS_MAXSIZE,
STATS_NOTC,
STATS_DEVICE,
STATS_NOINPUT,
STATS_MULTIPLE,
STATS_CONFTEST,
STATS_UNSUPPORTED,
STATS_OUTSTDOUT,
STATS_END
};
typedef unsigned uint32;
#include "mdfour.h"
void hash_start(void);
void hash_string(const char *s);
void hash_int(int x);
void hash_file(const char *fname);
char *hash_result(void);
void hash_buffer(const char *s, int len);
void cc_log(const char *format, ...);
void fatal(const char *msg);
void copy_fd(int fd_in, int fd_out);
int copy_file(const char *src, const char *dest);
int create_dir(const char *dir);
void x_asprintf(char **ptr, const char *format, ...);
char *x_strdup(const char *s);
void *x_realloc(void *ptr, size_t size);
void *x_malloc(size_t size);
void traverse(const char *dir, void (*fn)(const char *, struct stat *));
char *str_basename(const char *s);
char *dirname(char *s);
int lock_fd(int fd);
size_t file_size(struct stat *st);
int safe_open(const char *fname);
char *x_realpath(const char *path);
char *gnu_getcwd(void);
int create_empty_file(const char *fname);
const char *get_home_directory(void);
void stats_update(enum stats stat);
void stats_zero(void);
void stats_summary(void);
void stats_tocache(size_t size);
void stats_read(const char *stats_file, unsigned counters[STATS_END]);
void stats_set_limits(long maxfiles, long maxsize);
size_t value_units(const char *s);
void display_size(unsigned v);
void stats_set_sizes(const char *dir, size_t num_files, size_t total_size);
int unify_hash(const char *fname);
#ifndef HAVE_VASPRINTF
int vasprintf(char **, const char *, va_list );
#endif
#ifndef HAVE_ASPRINTF
int asprintf(char **ptr, const char *format, ...);
#endif
#ifndef HAVE_SNPRINTF
int snprintf(char *,size_t ,const char *, ...);
#endif
void cleanup_dir(const char *dir, size_t maxfiles, size_t maxsize);
void cleanup_all(const char *dir);
void wipe_all(const char *dir);
int execute(char **argv,
const char *path_stdout,
const char *path_stderr);
char *find_executable(const char *name, const char *exclude_name);
typedef struct {
char **argv;
int argc;
} ARGS;
ARGS *args_init(int , char **);
void args_add(ARGS *args, const char *s);
void args_add_prefix(ARGS *args, const char *s);
void args_pop(ARGS *args, int n);
void args_strip(ARGS *args, const char *prefix);
void args_remove_first(ARGS *args);
#if HAVE_COMPAR_FN_T
#define COMPAR_FN_T __compar_fn_t
#else
typedef int (*COMPAR_FN_T)(const void *, const void *);
#endif
/* work with silly DOS binary open */
#ifndef O_BINARY
#define O_BINARY 0
#endif
/* mkstemp() on some versions of cygwin don't handle binary files, so
override */
#ifdef __CYGWIN__
#undef HAVE_MKSTEMP
#endif

352
CCache/ccache.yo Normal file
View file

@ -0,0 +1,352 @@
mailto(bugs@ccache.samba.org)
manpage(ccache)(1)(April 2002)()()
manpagename(ccache)(a fast compiler cache)
manpagesynopsis()
ccache [OPTION]
ccache <compiler> [COMPILER OPTIONS]
<compiler> [COMPILER OPTIONS]
manpagedescription()
ccache is a compiler cache. It speeds up re-compilation of C/C++ code
by caching previous compiles and detecting when the same compile is
being done again.
manpagesection(OPTIONS SUMMARY)
Here is a summary of the options to ccache.
verb(
-s show statistics summary
-z zero statistics
-c run a cache cleanup
-C clear the cache completely
-F <maxfiles> set maximum files in cache
-M <maxsize> set maximum size of cache (use G, M or K)
-h this help page
-V print version number
)
manpageoptions()
These options only apply when you invoke ccache as "ccache". When
invoked as a compiler none of these options apply. In that case your
normal compiler options apply and you should refer to your compilers
documentation.
startdit()
dit(bf(-h)) Print a options summary page
dit(bf(-s)) Print the current statistics summary for the cache. The
statistics are stored spread across the subdirectories of the
cache. Using "ccache -s" adds up the statistics across all
subdirectories and prints the totals.
dit(bf(-z)) Zero the cache statistics.
dit(bf(-V)) Print the ccache version number
dit(bf(-c)) Clean the cache and re-calculate the cache file count and
size totals. Normally the -c option should not be necessary as ccache
keeps the cache below the specified limits at runtime and keeps
statistics up to date on each compile. This option is mostly useful
if you manually modify the cache contents or believe that the cache
size statistics may be inaccurate.
dit(bf(-C)) Clear the entire cache, removing all cached files.
dit(bf(-F maxfiles)) This sets the maximum number of files allowed in
the cache. The value is stored inside the cache directory and applies
to all future compiles. Due to the way the value is stored the actual
value used is always rounded down to the nearest multiple of 16.
dit(bf(-M maxsize)) This sets the maximum cache size. You can specify
a value in gigabytes, megabytes or kilobytes by appending a G, M or K
to the value. The default is gigabytes. The actual value stored is
rounded down to the nearest multiple of 16 kilobytes.
enddit()
manpagesection(INSTALLATION)
There are two ways to use ccache. You can either prefix your compile
commands with "ccache" or you can create a symbolic link between
ccache and the names of your compilers. The first method is most
convenient if you just want to try out ccache or wish to use it for
some specific projects. The second method is most useful for when you
wish to use ccache for all your compiles.
To install for usage by the first method just copy ccache to somewhere
in your path.
To install for the second method do something like this:
verb(
cp ccache /usr/local/bin/
ln -s /usr/local/bin/ccache /usr/local/bin/gcc
ln -s /usr/local/bin/ccache /usr/local/bin/g++
ln -s /usr/local/bin/ccache /usr/local/bin/cc
)
This will work as long as /usr/local/bin comes before the path to gcc
(which is usually in /usr/bin). After installing you may wish to run
"which gcc" to make sure that the correct link is being used.
Note! Do not use a hard link, use a symbolic link. A hardlink will
cause "interesting" problems.
manpagesection(EXTRA OPTIONS)
When run as a compiler front end ccache usually just takes the same
command line options as the compiler you are using. The only exception
to this is the option '--ccache-skip'. That option can be used to tell
ccache that the next option is definitely not a input filename, and
should be passed along to the compiler as-is.
The reason this can be important is that ccache does need to parse the
command line and determine what is an input filename and what is a
compiler option, as it needs the input filename to determine the name
of the resulting object file (among other things). The heuristic
ccache uses in this parse is that any string on the command line that
exists as a file is treated as an input file name (usually a C
file). By using --ccache-skip you can force an option to not be
treated as an input file name and instead be passed along to the
compiler as a command line option.
manpagesection(ENVIRONMENT VARIABLES)
ccache uses a number of environment variables to control operation. In
most cases you won't need any of these as the defaults will be fine.
startdit()
dit(bf(CCACHE_DIR)) the CCACHE_DIR environment variable specifies
where ccache will keep its cached compiler output. The default is
"$HOME/.ccache".
dit(bf(CCACHE_TEMPDIR)) the CCACHE_TEMPDIR environment variable specifies
where ccache will put temporary files. The default is the same as
CCACHE_DIR. Note that the CCACHE_TEMPDIR path must be on the same
filesystem as the CCACHE_DIR path, so that renames of files between
the two directories can work.
dit(bf(CCACHE_LOGFILE)) If you set the CCACHE_LOGFILE environment
variable then ccache will write some log information on cache hits
and misses in that file. This is useful for tracking down problems.
dit(bf(CCACHE_PATH)) You can optionally set CCACHE_PATH to a colon
separated path where ccache will look for the real compilers. If you
don't do this then ccache will look for the first executable matching
the compiler name in the normal PATH that isn't a symbolic link to
ccache itself.
dit(bf(CCACHE_CC)) You can optionally set CCACHE_CC to force the name
of the compiler to use. If you don't do this then ccache works it out
from the command line.
dit(bf(CCACHE_PREFIX)) This option adds a prefix to the command line
that ccache runs when invoking the compiler. Also see the section
below on using ccache with distcc.
dit(bf(CCACHE_DISABLE)) If you set the environment variable
CCACHE_DISABLE then ccache will just call the real compiler,
bypassing the cache completely.
dit(bf(CCACHE_READONLY)) the CCACHE_READONLY environment variable
tells ccache to attempt to use existing cached object files, but not
to try to add anything new to the cache. If you are using this because
your CCACHE_DIR is read-only, then you may find that you also need to
set CCACHE_TEMPDIR as otherwise ccache will fail to create the
temporary files.
dit(bf(CCACHE_CPP2)) If you set the environment variable CCACHE_CPP2
then ccache will not use the optimisation of avoiding the 2nd call to
the pre-processor by compiling the pre-processed output that was used
for finding the hash in the case of a cache miss. This is primarily a
debugging option, although it is possible that some unusual compilers
will have problems with the intermediate filename extensions used in
this optimisation, in which case this option could allow ccache to be
used.
dit(bf(CCACHE_NOSTATS)) If you set the environment variable
CCACHE_NOSTATS then ccache will not update the statistics files on
each compile.
dit(bf(CCACHE_NLEVELS)) The environment variable CCACHE_NLEVELS allows
you to choose the number of levels of hash in the cache directory. The
default is 2. The minimum is 1 and the maximum is 8.
dit(bf(CCACHE_HARDLINK)) If you set the environment variable
CCACHE_HARDLINK then ccache will attempt to use hard links from the
cache directory when creating the compiler output rather than using a
file copy. Using hard links is faster, but can confuse programs like
'make' that rely on modification times.
dit(bf(CCACHE_RECACHE)) This forces ccache to not use any cached
results, even if it finds them. New results are still cached, but
existing cache entries are ignored.
dit(bf(CCACHE_UMASK)) This sets the umask for ccache and all child
processes (such as the compiler). This is mostly useful when you wish
to share your cache with other users. Note that this also affects the
file permissions set on the object files created from your
compilations.
dit(bf(CCACHE_HASHDIR)) This tells ccache to hash the current working
directory when calculating the hash that is used to distinguish two
compiles. This prevents a problem with the storage of the current
working directory in the debug info of a object file, which can lead
ccache to give a cached object file that has the working directory in
the debug info set incorrectly. This option is off by default as the
incorrect setting of this debug info rarely causes problems. If you
strike problems with gdb not using the correct directory then enable
this option.
dit(bf(CCACHE_UNIFY)) If you set the environment variable CCACHE_UNIFY
then ccache will use the C/C++ unifier when hashing the pre-processor
output if -g is not used in the compile. The unifier is slower than a
normal hash, so setting this environment variable loses a little bit
of speed, but it means that ccache can take advantage of not
recompiling when the changes to the source code consist of
reformatting only. Note that using CCACHE_UNIFY changes the hash, so
cached compiles with CCACHE_UNIFY set cannot be used when
CCACHE_UNIFY is not set and vice versa. The reason the unifier is off
by default is that it can give incorrect line number information in
compiler warning messages.
dit(bf(CCACHE_EXTENSION)) Normally ccache tries to automatically
determine the extension to use for intermediate C pre-processor files
based on the type of file being compiled. Unfortunately this sometimes
doesn't work, for example when using the aCC compiler on HP-UX. On
systems like this you can use the CCACHE_EXTENSION option to override
the default. On HP-UX set this environment variable to "i" if you use
the aCC compiler.
enddit()
manpagesection(CACHE SIZE MANAGEMENT)
By default ccache has a one gigabyte limit on the cache size and no
maximum number of files. You can set a different limit using the
"ccache -M" and "ccache -F" options, which set the size and number of
files limits.
When these limits are reached ccache will reduce the cache to 20%
below the numbers you specified in order to avoid doing the cache
clean operation too often.
manpagesection(HOW IT WORKS)
The basic idea is to detect when you are compiling exactly the same
code a 2nd time and use the previously compiled output. You detect
that it is the same code by forming a hash of:
itemize(
it() the pre-processor output from running the compiler with -E
it() the command line options
it() the real compilers size and modification time
it() any stderr output generated by the compiler
)
These are hashed using md4 (a strong hash) and a cache file is formed
based on that hash result. When the same compilation is done a second
time ccache is able to supply the correct compiler output (including
all warnings etc) from the cache.
ccache has been carefully written to always produce exactly the same
compiler output that you would get without the cache. If you ever
discover a case where ccache changes the output of your compiler then
please let me know.
manpagesection(USING CCACHE WITH DISTCC)
distcc is a very useful program for distributing compilation across a
range of compiler servers. It is often useful to combine distcc with
ccache, so that compiles that are done are sped up by distcc, but that
ccache avoids the compile completely where possible.
To use distcc with ccache I recommend using the CCACHE_PREFIX
option. You just need to set the environment variable CCACHE_PREFIX to
'distcc' and ccache will prefix the command line used with the
compiler with the command 'distcc'.
manpagesection(SHARING A CACHE)
A group of developers can increase the cache hit rate by sharing a
cache directory. The hard links however cause unwanted side effects,
as all links to a cached file share the file's modification timestamp.
This results in false dependencies to be triggered by timestamp-based
build systems whenever another user links to an existing
file. Typically, users will see that their libraries and binaries are
relinked without reason. To share a cache without side effects, the
following conditions need to be met:
itemize(
it() Use the same bf(CCACHE_DIR) environment variable setting
it() Set the bf(CCACHE_NOLINK) environment variable
it() Make sure everyone sets the CCACHE_UMASK environment variable
to 002, this ensures that cached files are accessible to everyone in
the group.
it() Make sure that all users have write permission in the entire
cache directory (and that you trust all users of the shared cache).
it() Make sure that the setgid bit is set on all directories in the
cache. This tells the filesystem to inherit group ownership for new
directories. The command "chmod g+s `find $CCACHE_DIR -type d`" might
be useful for this.
)
manpagesection(HISTORY)
ccache was inspired by the compilercache shell script script written
by Erik Thiele and I would like to thank him for an excellent piece of
work. See
url(http://www.erikyyy.de/compilercache/)(http://www.erikyyy.de/compilercache/)
for the Erik's scripts.
I wrote ccache because I wanted to get a bit more speed out of a
compiler cache and I wanted to remove some of the limitations of the
shell-script version.
manpagesection(DIFFERENCES FROM COMPILERCACHE)
The biggest differences between Erik's compilercache script and ccache
are:
itemize(
it() ccache is written in C, which makes it a bit faster (calling out to
external programs is mostly what slowed down the scripts).
it() ccache can automatically find the real compiler
it() ccache keeps statistics on hits/misses
it() ccache can do automatic cache management
it() ccache can cache compiler output that includes warnings. In many
cases this gives ccache a much higher cache hit rate.
it() ccache can handle a much wider ranger of compiler options
it() ccache avoids a double call to cpp on a cache miss
)
manpagesection(BUGS)
When the cache is stored on an NFS filesystem, the filesystem must be
exported with the bf(no_subtree_check) option to make renames between
directories reliable.
manpagesection(CREDITS)
Thanks to the following people for their contributions to ccache
itemize(
it() Erik Thiele for the original compilercache script
it() Luciano Rocha for the idea of compiling the pre-processor output
to avoid a 2nd cpp pass
it() Paul Russell for many suggestions and the debian packaging
)
manpageauthor()
ccache was written by Andrew Tridgell
url(http://samba.org/~tridge/)(http://samba.org/~tridge/)
If you wish to report a problem or make a suggestion then please email
bugs@ccache.samba.org
ccache is released under the GNU General Public License version 2 or
later. Please see the file COPYING for license details.

193
CCache/cleanup.c Normal file
View file

@ -0,0 +1,193 @@
/*
Copyright (C) Andrew Tridgell 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
functions to cleanup the cache directory when it gets too large
*/
#include "ccache.h"
static struct files {
char *fname;
time_t mtime;
size_t size;
} **files;
static unsigned allocated;
static unsigned num_files;
static size_t total_size;
static size_t total_files;
static size_t size_threshold;
static size_t files_threshold;
/* file comparison function to try to delete the oldest files first */
static int files_compare(struct files **f1, struct files **f2)
{
if ((*f2)->mtime == (*f1)->mtime) {
return strcmp((*f2)->fname, (*f1)->fname);
}
if ((*f2)->mtime > (*f1)->mtime) {
return -1;
}
return 1;
}
/* this builds the list of files in the cache */
static void traverse_fn(const char *fname, struct stat *st)
{
char *p;
if (!S_ISREG(st->st_mode)) return;
p = str_basename(fname);
if (strcmp(p, "stats") == 0) {
free(p);
return;
}
free(p);
if (num_files == allocated) {
allocated = 10000 + num_files*2;
files = (struct files **)x_realloc(files,
sizeof(struct files *)*allocated);
}
files[num_files] = (struct files *)x_malloc(sizeof(struct files));
files[num_files]->fname = x_strdup(fname);
files[num_files]->mtime = st->st_mtime;
files[num_files]->size = file_size(st) / 1024;
total_size += files[num_files]->size;
num_files++;
}
/* sort the files we've found and delete the oldest ones until we are
below the thresholds */
static void sort_and_clean(void)
{
unsigned i;
if (num_files > 1) {
/* sort in ascending data order */
qsort(files, num_files, sizeof(struct files *),
(COMPAR_FN_T)files_compare);
}
/* delete enough files to bring us below the threshold */
for (i=0;i<num_files; i++) {
if ((size_threshold==0 || total_size < size_threshold) &&
(files_threshold==0 || (num_files-i) < files_threshold)) break;
if (unlink(files[i]->fname) != 0 && errno != ENOENT) {
fprintf(stderr, "unlink %s - %s\n",
files[i]->fname, strerror(errno));
continue;
}
total_size -= files[i]->size;
}
total_files = num_files - i;
}
/* cleanup in one cache subdir */
void cleanup_dir(const char *dir, size_t maxfiles, size_t maxsize)
{
unsigned i;
size_threshold = maxsize * LIMIT_MULTIPLE;
files_threshold = maxfiles * LIMIT_MULTIPLE;
num_files = 0;
total_size = 0;
/* build a list of files */
traverse(dir, traverse_fn);
/* clean the cache */
sort_and_clean();
stats_set_sizes(dir, total_files, total_size);
/* free it up */
for (i=0;i<num_files;i++) {
free(files[i]->fname);
free(files[i]);
files[i] = NULL;
}
if (files) free(files);
allocated = 0;
files = NULL;
num_files = 0;
total_size = 0;
}
/* cleanup in all cache subdirs */
void cleanup_all(const char *dir)
{
unsigned counters[STATS_END];
char *dname, *sfile;
int i;
for (i=0;i<=0xF;i++) {
x_asprintf(&dname, "%s/%1x", dir, i);
x_asprintf(&sfile, "%s/%1x/stats", dir, i);
memset(counters, 0, sizeof(counters));
stats_read(sfile, counters);
cleanup_dir(dname,
counters[STATS_MAXFILES],
counters[STATS_MAXSIZE]);
free(dname);
free(sfile);
}
}
/* traverse function for wiping files */
static void wipe_fn(const char *fname, struct stat *st)
{
char *p;
if (!S_ISREG(st->st_mode)) return;
p = str_basename(fname);
if (strcmp(p, "stats") == 0) {
free(p);
return;
}
free(p);
unlink(fname);
}
/* wipe all cached files in all subdirs */
void wipe_all(const char *dir)
{
char *dname;
int i;
for (i=0;i<=0xF;i++) {
x_asprintf(&dname, "%s/%1x", dir, i);
traverse(dir, wipe_fn);
free(dname);
}
/* and fix the counters */
cleanup_all(dir);
}

100
CCache/config.h.in Normal file
View file

@ -0,0 +1,100 @@
/* config.h.in. Generated from configure.in by autoheader. */
/* Define to 1 if you have the `asprintf' function. */
#undef HAVE_ASPRINTF
/* */
#undef HAVE_C99_VSNPRINTF
/* */
#undef HAVE_COMPAR_FN_T
/* Define to 1 if you have the <ctype.h> header file. */
#undef HAVE_CTYPE_H
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
*/
#undef HAVE_DIRENT_H
/* Define to 1 if you have the `gethostname' function. */
#undef HAVE_GETHOSTNAME
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mkstemp' function. */
#undef HAVE_MKSTEMP
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
#undef HAVE_NDIR_H
/* Define to 1 if you have the `realpath' function. */
#undef HAVE_REALPATH
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_DIR_H
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_NDIR_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#undef HAVE_SYS_WAIT_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `vasprintf' function. */
#undef HAVE_VASPRINTF
/* Define to 1 if you have the `vsnprintf' function. */
#undef HAVE_VSNPRINTF
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Define _GNU_SOURCE so that we get all necessary prototypes */
#undef _GNU_SOURCE

4896
CCache/configure vendored Executable file

File diff suppressed because it is too large Load diff

72
CCache/configure.in Normal file
View file

@ -0,0 +1,72 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT()
AC_PREREQ(2.52)
AC_MSG_NOTICE([Configuring ccache])
AC_CONFIG_HEADER(config.h)
dnl Checks for programs.
AC_PROG_CC
AC_PROG_CPP
AC_PROG_INSTALL
AC_DEFINE([_GNU_SOURCE], 1,
[Define _GNU_SOURCE so that we get all necessary prototypes])
# If GCC, turn on warnings.
if test "x$GCC" = "xyes"
then
CFLAGS="$CFLAGS -Wall -W"
else
CFLAGS="$CFLAGS -O"
fi
AC_HEADER_DIRENT
AC_HEADER_TIME
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(ctype.h strings.h stdlib.h string.h pwd.h)
AC_CHECK_FUNCS(realpath snprintf vsnprintf vasprintf asprintf mkstemp)
AC_CHECK_FUNCS(gethostname getpwuid)
AC_CACHE_CHECK([for compar_fn_t in stdlib.h],ccache_cv_COMPAR_FN_T, [
AC_TRY_COMPILE(
[#include <stdlib.h>],
[
void test_fn(void) { qsort(NULL, 0, 0, (__compar_fn_t)NULL); }
],
ccache_cv_COMPAR_FN_T=yes,ccache_cv_COMPAR_FN_T=no)])
if test x"$ccache_cv_COMPAR_FN_T" = x"yes"; then
AC_DEFINE(HAVE_COMPAR_FN_T, 1, [ ])
fi
AC_CACHE_CHECK([for C99 vsnprintf],ccache_cv_HAVE_C99_VSNPRINTF,[
AC_TRY_RUN([
#include <sys/types.h>
#include <stdarg.h>
void foo(const char *format, ...) {
va_list ap;
int len;
char buf[5];
va_start(ap, format);
len = vsnprintf(0, 0, format, ap);
va_end(ap);
if (len != 5) exit(1);
if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1);
exit(0);
}
main() { foo("hello"); }
],
ccache_cv_HAVE_C99_VSNPRINTF=yes,ccache_cv_HAVE_C99_VSNPRINTF=no,ccache_cv_HAVE_C99_VSNPRINTF=cross)])
if test x"$ccache_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [ ])
fi
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

129
CCache/execute.c Normal file
View file

@ -0,0 +1,129 @@
/*
Copyright (C) Andrew Tridgell 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ccache.h"
/*
execute a compiler backend, capturing all output to the given paths
the full path to the compiler to run is in argv[0]
*/
int execute(char **argv,
const char *path_stdout,
const char *path_stderr)
{
pid_t pid;
int status;
pid = fork();
if (pid == -1) fatal("Failed to fork");
if (pid == 0) {
int fd;
unlink(path_stdout);
fd = open(path_stdout, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
if (fd == -1) {
exit(STATUS_NOCACHE);
}
dup2(fd, 1);
close(fd);
unlink(path_stderr);
fd = open(path_stderr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
if (fd == -1) {
exit(STATUS_NOCACHE);
}
dup2(fd, 2);
close(fd);
exit(execv(argv[0], argv));
}
if (waitpid(pid, &status, 0) != pid) {
fatal("waitpid failed");
}
if (WEXITSTATUS(status) == 0 && WIFSIGNALED(status)) {
return -1;
}
return WEXITSTATUS(status);
}
/*
find an executable by name in $PATH. Exclude any that are links to exclude_name
*/
char *find_executable(const char *name, const char *exclude_name)
{
char *path;
char *tok;
struct stat st1, st2;
if (*name == '/') {
return x_strdup(name);
}
path = getenv("CCACHE_PATH");
if (!path) {
path = getenv("PATH");
}
if (!path) {
cc_log("no PATH variable!?\n");
return NULL;
}
path = x_strdup(path);
/* search the path looking for the first compiler of the right name
that isn't us */
for (tok=strtok(path,":"); tok; tok = strtok(NULL, ":")) {
char *fname;
x_asprintf(&fname, "%s/%s", tok, name);
/* look for a normal executable file */
if (access(fname, X_OK) == 0 &&
lstat(fname, &st1) == 0 &&
stat(fname, &st2) == 0 &&
S_ISREG(st2.st_mode)) {
/* if its a symlink then ensure it doesn't
point at something called exclude_name */
if (S_ISLNK(st1.st_mode)) {
char *buf = x_realpath(fname);
if (buf) {
char *p = str_basename(buf);
if (strcmp(p, exclude_name) == 0) {
/* its a link to "ccache" ! */
free(p);
free(buf);
continue;
}
free(buf);
free(p);
}
}
/* found it! */
free(path);
return fname;
}
free(fname);
}
return NULL;
}

80
CCache/hash.c Normal file
View file

@ -0,0 +1,80 @@
/*
Copyright (C) Andrew Tridgell 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
simple front-end functions to mdfour code
*/
#include "ccache.h"
static struct mdfour md;
void hash_buffer(const char *s, int len)
{
mdfour_update(&md, (unsigned char *)s, len);
}
void hash_start(void)
{
mdfour_begin(&md);
}
void hash_string(const char *s)
{
hash_buffer(s, strlen(s));
}
void hash_int(int x)
{
hash_buffer((char *)&x, sizeof(x));
}
/* add contents of a file to the hash */
void hash_file(const char *fname)
{
char buf[1024];
int fd, n;
fd = open(fname, O_RDONLY|O_BINARY);
if (fd == -1) {
cc_log("Failed to open %s\n", fname);
fatal("hash_file");
}
while ((n = read(fd, buf, sizeof(buf))) > 0) {
hash_buffer(buf, n);
}
close(fd);
}
/* return the hash result as a static string */
char *hash_result(void)
{
unsigned char sum[16];
static char ret[53];
int i;
hash_buffer(NULL, 0);
mdfour_result(&md, sum);
for (i=0;i<16;i++) {
sprintf(&ret[i*2], "%02x", (unsigned)sum[i]);
}
sprintf(&ret[i*2], "-%u", (unsigned)md.totalN);
return ret;
}

238
CCache/install-sh Executable file
View file

@ -0,0 +1,238 @@
#! /bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
#
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

284
CCache/mdfour.c Normal file
View file

@ -0,0 +1,284 @@
/*
a implementation of MD4 designed for use in the SMB authentication protocol
Copyright (C) Andrew Tridgell 1997-1998.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ccache.h"
/* NOTE: This code makes no attempt to be fast!
It assumes that a int is at least 32 bits long
*/
static struct mdfour *m;
#define MASK32 (0xffffffff)
#define F(X,Y,Z) ((((X)&(Y)) | ((~(X))&(Z))))
#define G(X,Y,Z) ((((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))))
#define H(X,Y,Z) (((X)^(Y)^(Z)))
#define lshift(x,s) (((((x)<<(s))&MASK32) | (((x)>>(32-(s)))&MASK32)))
#define ROUND1(a,b,c,d,k,s) a = lshift((a + F(b,c,d) + M[k])&MASK32, s)
#define ROUND2(a,b,c,d,k,s) a = lshift((a + G(b,c,d) + M[k] + 0x5A827999)&MASK32,s)
#define ROUND3(a,b,c,d,k,s) a = lshift((a + H(b,c,d) + M[k] + 0x6ED9EBA1)&MASK32,s)
/* this applies md4 to 64 byte chunks */
static void mdfour64(uint32 *M)
{
uint32 AA, BB, CC, DD;
uint32 A,B,C,D;
A = m->A; B = m->B; C = m->C; D = m->D;
AA = A; BB = B; CC = C; DD = D;
ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
A += AA; B += BB;
C += CC; D += DD;
A &= MASK32; B &= MASK32;
C &= MASK32; D &= MASK32;
m->A = A; m->B = B; m->C = C; m->D = D;
}
static void copy64(uint32 *M, const unsigned char *in)
{
int i;
for (i=0;i<16;i++)
M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
(in[i*4+1]<<8) | (in[i*4+0]<<0);
}
static void copy4(unsigned char *out,uint32 x)
{
out[0] = x&0xFF;
out[1] = (x>>8)&0xFF;
out[2] = (x>>16)&0xFF;
out[3] = (x>>24)&0xFF;
}
void mdfour_begin(struct mdfour *md)
{
md->A = 0x67452301;
md->B = 0xefcdab89;
md->C = 0x98badcfe;
md->D = 0x10325476;
md->totalN = 0;
md->tail_len = 0;
}
static void mdfour_tail(const unsigned char *in, int n)
{
unsigned char buf[128];
uint32 M[16];
uint32 b;
m->totalN += n;
b = m->totalN * 8;
memset(buf, 0, 128);
if (n) memcpy(buf, in, n);
buf[n] = 0x80;
if (n <= 55) {
copy4(buf+56, b);
copy64(M, buf);
mdfour64(M);
} else {
copy4(buf+120, b);
copy64(M, buf);
mdfour64(M);
copy64(M, buf+64);
mdfour64(M);
}
}
void mdfour_update(struct mdfour *md, const unsigned char *in, int n)
{
uint32 M[16];
m = md;
if (in == NULL) {
mdfour_tail(md->tail, md->tail_len);
return;
}
if (md->tail_len) {
int len = 64 - md->tail_len;
if (len > n) len = n;
memcpy(md->tail+md->tail_len, in, len);
md->tail_len += len;
n -= len;
in += len;
if (md->tail_len == 64) {
copy64(M, md->tail);
mdfour64(M);
m->totalN += 64;
md->tail_len = 0;
}
}
while (n >= 64) {
copy64(M, in);
mdfour64(M);
in += 64;
n -= 64;
m->totalN += 64;
}
if (n) {
memcpy(md->tail, in, n);
md->tail_len = n;
}
}
void mdfour_result(struct mdfour *md, unsigned char *out)
{
m = md;
copy4(out, m->A);
copy4(out+4, m->B);
copy4(out+8, m->C);
copy4(out+12, m->D);
}
void mdfour(unsigned char *out, const unsigned char *in, int n)
{
struct mdfour md;
mdfour_begin(&md);
mdfour_update(&md, in, n);
mdfour_update(&md, NULL, 0);
mdfour_result(&md, out);
}
#ifdef TEST_MDFOUR
static void file_checksum1(char *fname)
{
int fd, i;
struct mdfour md;
unsigned char buf[1024], sum[16];
unsigned chunk;
fd = open(fname,O_RDONLY|O_BINARY);
if (fd == -1) {
perror("fname");
exit(1);
}
chunk = 1 + random() % (sizeof(buf) - 1);
mdfour_begin(&md);
while (1) {
int n = read(fd, buf, chunk);
if (n >= 0) {
mdfour_update(&md, buf, n);
}
if (n < chunk) break;
}
close(fd);
mdfour_update(&md, NULL, 0);
mdfour_result(&md, sum);
for (i=0;i<16;i++)
printf("%02x", sum[i]);
printf("\n");
}
#if 0
#include "../md4.h"
static void file_checksum2(char *fname)
{
int fd, i;
MDstruct md;
unsigned char buf[64], sum[16];
fd = open(fname,O_RDONLY|O_BINARY);
if (fd == -1) {
perror("fname");
exit(1);
}
MDbegin(&md);
while (1) {
int n = read(fd, buf, sizeof(buf));
if (n <= 0) break;
MDupdate(&md, buf, n*8);
}
if (!md.done) {
MDupdate(&md, buf, 0);
}
close(fd);
memcpy(sum, md.buffer, 16);
for (i=0;i<16;i++)
printf("%02x", sum[i]);
printf("\n");
}
#endif
int main(int argc, char *argv[])
{
file_checksum1(argv[1]);
#if 0
file_checksum2(argv[1]);
#endif
return 0;
}
#endif

36
CCache/mdfour.h Normal file
View file

@ -0,0 +1,36 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
a implementation of MD4 designed for use in the SMB authentication protocol
Copyright (C) Andrew Tridgell 1997-1998.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
struct mdfour {
uint32 A, B, C, D;
uint32 totalN;
unsigned char tail[64];
unsigned tail_len;
};
void mdfour_begin(struct mdfour *md);
void mdfour_update(struct mdfour *md, const unsigned char *in, int n);
void mdfour_result(struct mdfour *md, unsigned char *out);
void mdfour(unsigned char *out, const unsigned char *in, int n);

5
CCache/packaging/README Normal file
View file

@ -0,0 +1,5 @@
These packaging files are contributd by users of ccache. I do not
maintain them, and they may well need updating before you use them.
I don't distribute binary packages of ccache myself, but if you wish
to add ccache to a distribution then that's OK

View file

@ -0,0 +1,37 @@
Summary: Compiler Cache
Name: ccache
Version: 2.3
Release: 1
Group: Development/Languages
License: GPL
URL: http://ccache.samba.org/
Source: ccache-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-root
%description
ccache caches gcc output files
%prep
%setup -q
%build
%configure
make
install -d -m 0755 $RPM_BUILD_ROOT%{_bindir}
install -m 0755 ccache $RPM_BUILD_ROOT%{_bindir}
install -d -m 0755 $RPM_BUILD_ROOT%{_mandir}/man1
install -m 0644 ccache.1 $RPM_BUILD_ROOT%{_mandir}/man1
%files
%defattr(-,root,root)
%doc README
%{_mandir}/man1/ccache.1*
%{_bindir}/ccache
%clean
[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
%changelog
* Mon Apr 01 2002 Peter Jones <pjones@redhat.com>
- Created the package

962
CCache/snprintf.c Normal file
View file

@ -0,0 +1,962 @@
/*
* Copyright Patrick Powell 1995
* This code is based on code written by Patrick Powell (papowell@astart.com)
* It may be used for any purpose as long as this notice remains intact
* on all source code distributions
*/
/**************************************************************
* Original:
* Patrick Powell Tue Apr 11 09:48:21 PDT 1995
* A bombproof version of doprnt (dopr) included.
* Sigh. This sort of thing is always nasty do deal with. Note that
* the version here does not include floating point...
*
* snprintf() is used instead of sprintf() as it does limit checks
* for string length. This covers a nasty loophole.
*
* The other functions are there to prevent NULL pointers from
* causing nast effects.
*
* More Recently:
* Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
* This was ugly. It is still ugly. I opted out of floating point
* numbers, but the formatter understands just about everything
* from the normal C string format, at least as far as I can tell from
* the Solaris 2.5 printf(3S) man page.
*
* Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
* Ok, added some minimal floating point support, which means this
* probably requires libm on most operating systems. Don't yet
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
* was pretty badly broken, it just wasn't being exercised in ways
* which showed it, so that's been fixed. Also, formated the code
* to mutt conventions, and removed dead code left over from the
* original. Also, there is now a builtin-test, just compile with:
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
* and run snprintf for results.
*
* Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
* The PGP code was using unsigned hexadecimal formats.
* Unfortunately, unsigned formats simply didn't work.
*
* Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
* The original code assumed that both snprintf() and vsnprintf() were
* missing. Some systems only have snprintf() but not vsnprintf(), so
* the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
*
* Andrew Tridgell (tridge@samba.org) Oct 1998
* fixed handling of %.0f
* added test for HAVE_LONG_DOUBLE
*
* tridge@samba.org, idra@samba.org, April 2001
* got rid of fcvt code (twas buggy and made testing harder)
* added C99 semantics
*
**************************************************************/
#ifndef NO_CONFIG_H /* for some tests */
#include "config.h"
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#include <sys/types.h>
#include <stdarg.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
#include <stdio.h>
/* make the compiler happy with an empty file */
void dummy_snprintf(void) {}
#else
#ifdef HAVE_LONG_DOUBLE
#define LDOUBLE long double
#else
#define LDOUBLE double
#endif
#ifdef HAVE_LONG_LONG
#define LLONG long long
#else
#define LLONG long
#endif
static size_t dopr(char *buffer, size_t maxlen, const char *format,
va_list args);
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max);
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
long value, int base, int min, int max, int flags);
static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags);
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
/*
* dopr(): poor man's version of doprintf
*/
/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS 1
#define DP_S_MIN 2
#define DP_S_DOT 3
#define DP_S_MAX 4
#define DP_S_MOD 5
#define DP_S_CONV 6
#define DP_S_DONE 7
/* format flags - Bits */
#define DP_F_MINUS (1 << 0)
#define DP_F_PLUS (1 << 1)
#define DP_F_SPACE (1 << 2)
#define DP_F_NUM (1 << 3)
#define DP_F_ZERO (1 << 4)
#define DP_F_UP (1 << 5)
#define DP_F_UNSIGNED (1 << 6)
/* Conversion Flags */
#define DP_C_SHORT 1
#define DP_C_LONG 2
#define DP_C_LDOUBLE 3
#define DP_C_LLONG 4
#define char_to_int(p) ((p)- '0')
#ifndef MAX
#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
#endif
static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
{
char ch;
LLONG value;
LDOUBLE fvalue;
char *strvalue;
int min;
int max;
int state;
int flags;
int cflags;
size_t currlen;
state = DP_S_DEFAULT;
currlen = flags = cflags = min = 0;
max = -1;
ch = *format++;
while (state != DP_S_DONE) {
if (ch == '\0')
state = DP_S_DONE;
switch(state) {
case DP_S_DEFAULT:
if (ch == '%')
state = DP_S_FLAGS;
else
dopr_outch (buffer, &currlen, maxlen, ch);
ch = *format++;
break;
case DP_S_FLAGS:
switch (ch) {
case '-':
flags |= DP_F_MINUS;
ch = *format++;
break;
case '+':
flags |= DP_F_PLUS;
ch = *format++;
break;
case ' ':
flags |= DP_F_SPACE;
ch = *format++;
break;
case '#':
flags |= DP_F_NUM;
ch = *format++;
break;
case '0':
flags |= DP_F_ZERO;
ch = *format++;
break;
default:
state = DP_S_MIN;
break;
}
break;
case DP_S_MIN:
if (isdigit((unsigned char)ch)) {
min = 10*min + char_to_int (ch);
ch = *format++;
} else if (ch == '*') {
min = va_arg (args, int);
ch = *format++;
state = DP_S_DOT;
} else {
state = DP_S_DOT;
}
break;
case DP_S_DOT:
if (ch == '.') {
state = DP_S_MAX;
ch = *format++;
} else {
state = DP_S_MOD;
}
break;
case DP_S_MAX:
if (isdigit((unsigned char)ch)) {
if (max < 0)
max = 0;
max = 10*max + char_to_int (ch);
ch = *format++;
} else if (ch == '*') {
max = va_arg (args, int);
ch = *format++;
state = DP_S_MOD;
} else {
state = DP_S_MOD;
}
break;
case DP_S_MOD:
switch (ch) {
case 'h':
cflags = DP_C_SHORT;
ch = *format++;
break;
case 'l':
cflags = DP_C_LONG;
ch = *format++;
if (ch == 'l') { /* It's a long long */
cflags = DP_C_LLONG;
ch = *format++;
}
break;
case 'L':
cflags = DP_C_LDOUBLE;
ch = *format++;
break;
default:
break;
}
state = DP_S_CONV;
break;
case DP_S_CONV:
switch (ch) {
case 'd':
case 'i':
if (cflags == DP_C_SHORT)
value = va_arg (args, int);
else if (cflags == DP_C_LONG)
value = va_arg (args, long int);
else if (cflags == DP_C_LLONG)
value = va_arg (args, LLONG);
else
value = va_arg (args, int);
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
break;
case 'o':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (long)va_arg (args, unsigned LLONG);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
break;
case 'u':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (LLONG)va_arg (args, unsigned LLONG);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
break;
case 'X':
flags |= DP_F_UP;
case 'x':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (LLONG)va_arg (args, unsigned LLONG);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
break;
case 'f':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
/* um, floating point? */
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
break;
case 'E':
flags |= DP_F_UP;
case 'e':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
break;
case 'G':
flags |= DP_F_UP;
case 'g':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
break;
case 'c':
dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
break;
case 's':
strvalue = va_arg (args, char *);
if (!strvalue) strvalue = "(NULL)";
if (max == -1) {
max = strlen(strvalue);
}
if (min > 0 && max >= 0 && min > max) max = min;
fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
break;
case 'p':
strvalue = (char *)va_arg(args, void *);
fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
break;
case 'n':
if (cflags == DP_C_SHORT) {
short int *num;
num = va_arg (args, short int *);
*num = currlen;
} else if (cflags == DP_C_LONG) {
long int *num;
num = va_arg (args, long int *);
*num = (long int)currlen;
} else if (cflags == DP_C_LLONG) {
LLONG *num;
num = va_arg (args, LLONG *);
*num = (LLONG)currlen;
} else {
int *num;
num = va_arg (args, int *);
*num = currlen;
}
break;
case '%':
dopr_outch (buffer, &currlen, maxlen, ch);
break;
case 'w':
/* not supported yet, treat as next char */
ch = *format++;
break;
default:
/* Unknown, skip */
break;
}
ch = *format++;
state = DP_S_DEFAULT;
flags = cflags = min = 0;
max = -1;
break;
case DP_S_DONE:
break;
default:
/* hmm? */
break; /* some picky compilers need this */
}
}
if (maxlen != 0) {
if (currlen < maxlen - 1)
buffer[currlen] = '\0';
else if (maxlen > 0)
buffer[maxlen - 1] = '\0';
}
return currlen;
}
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max)
{
int padlen, strln; /* amount to pad */
int cnt = 0;
#ifdef DEBUG_SNPRINTF
printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
#endif
if (value == 0) {
value = "<NULL>";
}
for (strln = 0; value[strln]; ++strln); /* strlen */
padlen = min - strln;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justify */
while ((padlen > 0) && (cnt < max)) {
dopr_outch (buffer, currlen, maxlen, ' ');
--padlen;
++cnt;
}
while (*value && (cnt < max)) {
dopr_outch (buffer, currlen, maxlen, *value++);
++cnt;
}
while ((padlen < 0) && (cnt < max)) {
dopr_outch (buffer, currlen, maxlen, ' ');
++padlen;
++cnt;
}
}
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
long value, int base, int min, int max, int flags)
{
int signvalue = 0;
unsigned long uvalue;
char convert[20];
int place = 0;
int spadlen = 0; /* amount to space pad */
int zpadlen = 0; /* amount to zero pad */
int caps = 0;
if (max < 0)
max = 0;
uvalue = value;
if(!(flags & DP_F_UNSIGNED)) {
if( value < 0 ) {
signvalue = '-';
uvalue = -value;
} else {
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
signvalue = '+';
else if (flags & DP_F_SPACE)
signvalue = ' ';
}
}
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
do {
convert[place++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")
[uvalue % (unsigned)base ];
uvalue = (uvalue / (unsigned)base );
} while(uvalue && (place < 20));
if (place == 20) place--;
convert[place] = 0;
zpadlen = max - place;
spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
if (zpadlen < 0) zpadlen = 0;
if (spadlen < 0) spadlen = 0;
if (flags & DP_F_ZERO) {
zpadlen = MAX(zpadlen, spadlen);
spadlen = 0;
}
if (flags & DP_F_MINUS)
spadlen = -spadlen; /* Left Justifty */
#ifdef DEBUG_SNPRINTF
printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
zpadlen, spadlen, min, max, place);
#endif
/* Spaces */
while (spadlen > 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
--spadlen;
}
/* Sign */
if (signvalue)
dopr_outch (buffer, currlen, maxlen, signvalue);
/* Zeros */
if (zpadlen > 0) {
while (zpadlen > 0) {
dopr_outch (buffer, currlen, maxlen, '0');
--zpadlen;
}
}
/* Digits */
while (place > 0)
dopr_outch (buffer, currlen, maxlen, convert[--place]);
/* Left Justified spaces */
while (spadlen < 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
++spadlen;
}
}
static LDOUBLE abs_val(LDOUBLE value)
{
LDOUBLE result = value;
if (value < 0)
result = -value;
return result;
}
static LDOUBLE POW10(int exp)
{
LDOUBLE result = 1;
while (exp) {
result *= 10;
exp--;
}
return result;
}
static LLONG ROUND(LDOUBLE value)
{
LLONG intpart;
intpart = (LLONG)value;
value = value - intpart;
if (value >= 0.5) intpart++;
return intpart;
}
/* a replacement for modf that doesn't need the math library. Should
be portable, but slow */
static double my_modf(double x0, double *iptr)
{
int i;
long l;
double x = x0;
double f = 1.0;
for (i=0;i<100;i++) {
l = (long)x;
if (l <= (x+1) && l >= (x-1)) break;
x *= 0.1;
f *= 10.0;
}
if (i == 100) {
/* yikes! the number is beyond what we can handle. What do we do? */
(*iptr) = 0;
return 0;
}
if (i != 0) {
double i2;
double ret;
ret = my_modf(x0-l*f, &i2);
(*iptr) = l*f + i2;
return ret;
}
(*iptr) = l;
return x - (*iptr);
}
static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags)
{
int signvalue = 0;
double ufvalue;
char iconvert[311];
char fconvert[311];
int iplace = 0;
int fplace = 0;
int padlen = 0; /* amount to pad */
int zpadlen = 0;
int caps = 0;
int index;
double intpart;
double fracpart;
double temp;
/*
* AIX manpage says the default is 0, but Solaris says the default
* is 6, and sprintf on AIX defaults to 6
*/
if (max < 0)
max = 6;
ufvalue = abs_val (fvalue);
if (fvalue < 0) {
signvalue = '-';
} else {
if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
signvalue = '+';
} else {
if (flags & DP_F_SPACE)
signvalue = ' ';
}
}
#if 0
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
#endif
#if 0
if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
#endif
/*
* Sorry, we only support 16 digits past the decimal because of our
* conversion method
*/
if (max > 16)
max = 16;
/* We "cheat" by converting the fractional part to integer by
* multiplying by a factor of 10
*/
temp = ufvalue;
my_modf(temp, &intpart);
fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
if (fracpart >= POW10(max)) {
intpart++;
fracpart -= POW10(max);
}
/* Convert integer part */
do {
temp = intpart;
my_modf(intpart*0.1, &intpart);
temp = temp*0.1;
index = (int) ((temp -intpart +0.05)* 10.0);
/* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
/* printf ("%llf, %f, %x\n", temp, intpart, index); */
iconvert[iplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
} while (intpart && (iplace < 311));
if (iplace == 311) iplace--;
iconvert[iplace] = 0;
/* Convert fractional part */
if (fracpart)
{
do {
temp = fracpart;
my_modf(fracpart*0.1, &fracpart);
temp = temp*0.1;
index = (int) ((temp -fracpart +0.05)* 10.0);
/* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
/* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
fconvert[fplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
} while(fracpart && (fplace < 311));
if (fplace == 311) fplace--;
}
fconvert[fplace] = 0;
/* -1 for decimal point, another -1 if we are printing a sign */
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
zpadlen = max - fplace;
if (zpadlen < 0) zpadlen = 0;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justifty */
if ((flags & DP_F_ZERO) && (padlen > 0)) {
if (signvalue) {
dopr_outch (buffer, currlen, maxlen, signvalue);
--padlen;
signvalue = 0;
}
while (padlen > 0) {
dopr_outch (buffer, currlen, maxlen, '0');
--padlen;
}
}
while (padlen > 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
--padlen;
}
if (signvalue)
dopr_outch (buffer, currlen, maxlen, signvalue);
while (iplace > 0)
dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
#ifdef DEBUG_SNPRINTF
printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
#endif
/*
* Decimal point. This should probably use locale to find the correct
* char to print out.
*/
if (max > 0) {
dopr_outch (buffer, currlen, maxlen, '.');
while (fplace > 0)
dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
}
while (zpadlen > 0) {
dopr_outch (buffer, currlen, maxlen, '0');
--zpadlen;
}
while (padlen < 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
++padlen;
}
}
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
{
if (*currlen < maxlen) {
buffer[(*currlen)] = c;
}
(*currlen)++;
}
/* yes this really must be a ||. Don't muck with this (tridge) */
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
{
return dopr(str, count, fmt, args);
}
#endif
/* yes this really must be a ||. Don't muck wiith this (tridge)
*
* The logic for these two is that we need our own definition if the
* OS *either* has no definition of *sprintf, or if it does have one
* that doesn't work properly according to the autoconf test. Perhaps
* these should really be smb_snprintf to avoid conflicts with buggy
* linkers? -- mbp
*/
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_SNPRINTF)
int snprintf(char *str,size_t count,const char *fmt,...)
{
size_t ret;
va_list ap;
va_start(ap, fmt);
ret = vsnprintf(str, count, fmt, ap);
va_end(ap);
return ret;
}
#endif
#endif
#ifndef HAVE_VASPRINTF
int vasprintf(char **ptr, const char *format, va_list ap)
{
int ret;
ret = vsnprintf(0, 0, format, ap);
if (ret <= 0) return ret;
(*ptr) = (char *)malloc(ret+1);
if (!*ptr) return -1;
ret = vsnprintf(*ptr, ret+1, format, ap);
return ret;
}
#endif
#ifndef HAVE_ASPRINTF
int asprintf(char **ptr, const char *format, ...)
{
va_list ap;
int ret;
*ptr = 0;
va_start(ap, format);
ret = vasprintf(ptr, format, ap);
va_end(ap);
return ret;
}
#endif
#ifndef HAVE_VSYSLOG
#ifdef HAVE_SYSLOG
void vsyslog (int facility_priority, char *format, va_list arglist)
{
char *msg = 0;
vasprintf(&msg, format, arglist);
if (!msg)
return;
syslog(facility_priority, "%s", msg);
free(msg);
}
#endif /* HAVE_SYSLOG */
#endif /* HAVE_VSYSLOG */
#ifdef TEST_SNPRINTF
int sprintf(char *str,const char *fmt,...);
int main (void)
{
char buf1[1024];
char buf2[1024];
char *fp_fmt[] = {
"%1.1f",
"%-1.5f",
"%1.5f",
"%123.9f",
"%10.5f",
"% 10.5f",
"%+22.9f",
"%+4.9f",
"%01.3f",
"%4f",
"%3.1f",
"%3.2f",
"%.0f",
"%f",
"-16.16f",
0
};
double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
0.9996, 1.996, 4.136, 0};
char *int_fmt[] = {
"%-1.5d",
"%1.5d",
"%123.9d",
"%5.5d",
"%10.5d",
"% 10.5d",
"%+22.33d",
"%01.3d",
"%4d",
"%d",
0
};
long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
char *str_fmt[] = {
"10.5s",
"5.10s",
"10.1s",
"0.10s",
"10.0s",
"1.10s",
"%s",
"%.1s",
"%.10s",
"%10s",
0
};
char *str_vals[] = {"hello", "a", "", "a longer string", 0};
int x, y;
int fail = 0;
int num = 0;
printf ("Testing snprintf format codes against system sprintf...\n");
for (x = 0; fp_fmt[x] ; x++) {
for (y = 0; fp_nums[y] != 0 ; y++) {
int l1 = snprintf(0, 0, fp_fmt[x], fp_nums[y]);
int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
sprintf (buf2, fp_fmt[x], fp_nums[y]);
if (strcmp (buf1, buf2)) {
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
fp_fmt[x], buf1, buf2);
fail++;
}
if (l1 != l2) {
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
fail++;
}
num++;
}
}
for (x = 0; int_fmt[x] ; x++) {
for (y = 0; int_nums[y] != 0 ; y++) {
int l1 = snprintf(0, 0, int_fmt[x], int_nums[y]);
int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
sprintf (buf2, int_fmt[x], int_nums[y]);
if (strcmp (buf1, buf2)) {
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
int_fmt[x], buf1, buf2);
fail++;
}
if (l1 != l2) {
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
fail++;
}
num++;
}
}
for (x = 0; str_fmt[x] ; x++) {
for (y = 0; str_vals[y] != 0 ; y++) {
int l1 = snprintf(0, 0, str_fmt[x], str_vals[y]);
int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
sprintf (buf2, str_fmt[x], str_vals[y]);
if (strcmp (buf1, buf2)) {
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
str_fmt[x], buf1, buf2);
fail++;
}
if (l1 != l2) {
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
fail++;
}
num++;
}
}
printf ("%d tests failed out of %d.\n", fail, num);
printf("seeing how many digits we support\n");
{
double v0 = 0.12345678901234567890123456789012345678901;
for (x=0; x<100; x++) {
snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x));
sprintf(buf2, "%1.1f", v0*pow(10, x));
if (strcmp(buf1, buf2)) {
printf("we seem to support %d digits\n", x-1);
break;
}
}
}
return 0;
}
#endif /* SNPRINTF_TEST */

354
CCache/stats.c Normal file
View file

@ -0,0 +1,354 @@
/*
Copyright (C) Andrew Tridgell 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
routines to handle the stats files
the stats file is stored one per cache subdirectory to make this more
scalable
*/
#include "ccache.h"
extern char *stats_file;
extern char *cache_dir;
#define STATS_VERSION 1
#define FLAG_NOZERO 1 /* don't zero with the -z option */
#define FLAG_ALWAYS 2 /* always show, even if zero */
static struct {
enum stats stat;
char *message;
void (*fn)(unsigned );
unsigned flags;
} stats_info[] = {
{ STATS_CACHED, "cache hit ", NULL, FLAG_ALWAYS },
{ STATS_TOCACHE, "cache miss ", NULL, FLAG_ALWAYS },
{ STATS_LINK, "called for link ", NULL, 0 },
{ STATS_MULTIPLE, "multiple source files ", NULL, 0 },
{ STATS_STDOUT, "compiler produced stdout ", NULL, 0 },
{ STATS_STATUS, "compile failed ", NULL, 0 },
{ STATS_ERROR, "ccache internal error ", NULL, 0 },
{ STATS_PREPROCESSOR, "preprocessor error ", NULL, 0 },
{ STATS_COMPILER, "couldn't find the compiler ", NULL, 0 },
{ STATS_MISSING, "cache file missing ", NULL, 0 },
{ STATS_ARGS, "bad compiler arguments ", NULL, 0 },
{ STATS_NOTC, "not a C/C++ file ", NULL, 0 },
{ STATS_CONFTEST, "autoconf compile/link ", NULL, 0 },
{ STATS_UNSUPPORTED, "unsupported compiler option ", NULL, 0 },
{ STATS_OUTSTDOUT, "output to stdout ", NULL, 0 },
{ STATS_DEVICE, "output to a non-regular file ", NULL, 0 },
{ STATS_NOINPUT, "no input file ", NULL, 0 },
{ STATS_NUMFILES, "files in cache ", NULL, FLAG_NOZERO|FLAG_ALWAYS },
{ STATS_TOTALSIZE, "cache size ", display_size , FLAG_NOZERO|FLAG_ALWAYS },
{ STATS_MAXFILES, "max files ", NULL, FLAG_NOZERO },
{ STATS_MAXSIZE, "max cache size ", display_size, FLAG_NOZERO },
{ STATS_NONE, NULL, NULL, 0 }
};
/* parse a stats file from a buffer - adding to the counters */
static void parse_stats(unsigned counters[STATS_END], char *buf)
{
int i;
char *p, *p2;
p = buf;
for (i=0;i<STATS_END;i++) {
counters[i] += strtol(p, &p2, 10);
if (!p2 || p2 == p) break;
p = p2;
}
}
/* write out a stats file */
static void write_stats(int fd, unsigned counters[STATS_END])
{
int i;
int len = 0;
char buf[1024];
for (i=0;i<STATS_END;i++) {
len += snprintf(buf+len, sizeof(buf)-(len+1), "%u ", counters[i]);
if (len >= (int)sizeof(buf)-1) fatal("stats too long?!");
}
len += snprintf(buf+len, sizeof(buf)-(len+1), "\n");
if (len >= (int)sizeof(buf)-1) fatal("stats too long?!");
lseek(fd, 0, SEEK_SET);
write(fd, buf, len);
}
/* fill in some default stats values */
static void stats_default(unsigned counters[STATS_END])
{
counters[STATS_MAXSIZE] += DEFAULT_MAXSIZE / 16;
}
/* read in the stats from one dir and add to the counters */
static void stats_read_fd(int fd, unsigned counters[STATS_END])
{
char buf[1024];
int len;
len = read(fd, buf, sizeof(buf)-1);
if (len <= 0) {
stats_default(counters);
return;
}
buf[len] = 0;
parse_stats(counters, buf);
}
/* update the stats counter for this compile */
static void stats_update_size(enum stats stat, size_t size)
{
int fd;
unsigned counters[STATS_END];
int need_cleanup = 0;
if (getenv("CCACHE_NOSTATS")) return;
if (!stats_file) {
if (!cache_dir) return;
x_asprintf(&stats_file, "%s/stats", cache_dir);
}
/* open safely to try to prevent symlink races */
fd = safe_open(stats_file);
/* still can't get it? don't bother ... */
if (fd == -1) return;
memset(counters, 0, sizeof(counters));
if (lock_fd(fd) != 0) return;
/* read in the old stats */
stats_read_fd(fd, counters);
/* update them */
counters[stat]++;
/* on a cache miss we up the file count and size */
if (stat == STATS_TOCACHE) {
counters[STATS_NUMFILES] += 2;
counters[STATS_TOTALSIZE] += size;
}
/* and write them out */
write_stats(fd, counters);
close(fd);
/* we might need to cleanup if the cache has now got too big */
if (counters[STATS_MAXFILES] != 0 &&
counters[STATS_NUMFILES] > counters[STATS_MAXFILES]) {
need_cleanup = 1;
}
if (counters[STATS_MAXSIZE] != 0 &&
counters[STATS_TOTALSIZE] > counters[STATS_MAXSIZE]) {
need_cleanup = 1;
}
if (need_cleanup) {
char *p = dirname(stats_file);
cleanup_dir(p, counters[STATS_MAXFILES], counters[STATS_MAXSIZE]);
free(p);
}
}
/* record a cache miss */
void stats_tocache(size_t size)
{
/* convert size to kilobytes */
size = size / 1024;
stats_update_size(STATS_TOCACHE, size);
}
/* update a normal stat */
void stats_update(enum stats stat)
{
stats_update_size(stat, 0);
}
/* read in the stats from one dir and add to the counters */
void stats_read(const char *stats_file, unsigned counters[STATS_END])
{
int fd;
fd = open(stats_file, O_RDONLY|O_BINARY);
if (fd == -1) {
stats_default(counters);
return;
}
lock_fd(fd);
stats_read_fd(fd, counters);
close(fd);
}
/* sum and display the total stats for all cache dirs */
void stats_summary(void)
{
int dir, i;
unsigned counters[STATS_END];
memset(counters, 0, sizeof(counters));
/* add up the stats in each directory */
for (dir=-1;dir<=0xF;dir++) {
char *fname;
if (dir == -1) {
x_asprintf(&fname, "%s/stats", cache_dir);
} else {
x_asprintf(&fname, "%s/%1x/stats", cache_dir, dir);
}
stats_read(fname, counters);
free(fname);
/* oh what a nasty hack ... */
if (dir == -1) {
counters[STATS_MAXSIZE] = 0;
}
}
printf("cache directory %s\n", cache_dir);
/* and display them */
for (i=0;stats_info[i].message;i++) {
enum stats stat = stats_info[i].stat;
if (counters[stat] == 0 &&
!(stats_info[i].flags & FLAG_ALWAYS)) {
continue;
}
printf("%s ", stats_info[i].message);
if (stats_info[i].fn) {
stats_info[i].fn(counters[stat]);
printf("\n");
} else {
printf("%8u\n", counters[stat]);
}
}
}
/* zero all the stats structures */
void stats_zero(void)
{
int dir, fd;
unsigned i;
char *fname;
unsigned counters[STATS_END];
x_asprintf(&fname, "%s/stats", cache_dir);
unlink(fname);
free(fname);
for (dir=0;dir<=0xF;dir++) {
x_asprintf(&fname, "%s/%1x/stats", cache_dir, dir);
fd = safe_open(fname);
if (fd == -1) {
free(fname);
continue;
}
memset(counters, 0, sizeof(counters));
lock_fd(fd);
stats_read_fd(fd, counters);
for (i=0;stats_info[i].message;i++) {
if (!(stats_info[i].flags & FLAG_NOZERO)) {
counters[stats_info[i].stat] = 0;
}
}
write_stats(fd, counters);
close(fd);
free(fname);
}
}
/* set the per directory limits */
void stats_set_limits(long maxfiles, long maxsize)
{
int dir;
unsigned counters[STATS_END];
if (maxfiles != -1) {
maxfiles /= 16;
}
if (maxsize != -1) {
maxsize /= 16;
}
create_dir(cache_dir);
/* set the limits in each directory */
for (dir=0;dir<=0xF;dir++) {
char *fname, *cdir;
int fd;
x_asprintf(&cdir, "%s/%1x", cache_dir, dir);
create_dir(cdir);
x_asprintf(&fname, "%s/stats", cdir);
free(cdir);
memset(counters, 0, sizeof(counters));
fd = safe_open(fname);
if (fd != -1) {
lock_fd(fd);
stats_read_fd(fd, counters);
if (maxfiles != -1) {
counters[STATS_MAXFILES] = maxfiles;
}
if (maxsize != -1) {
counters[STATS_MAXSIZE] = maxsize;
}
write_stats(fd, counters);
close(fd);
}
free(fname);
}
}
/* set the per directory sizes */
void stats_set_sizes(const char *dir, size_t num_files, size_t total_size)
{
int fd;
unsigned counters[STATS_END];
char *stats_file;
create_dir(dir);
x_asprintf(&stats_file, "%s/stats", dir);
memset(counters, 0, sizeof(counters));
fd = safe_open(stats_file);
if (fd != -1) {
lock_fd(fd);
stats_read_fd(fd, counters);
counters[STATS_NUMFILES] = num_files;
counters[STATS_TOTALSIZE] = total_size;
write_stats(fd, counters);
close(fd);
}
free(stats_file);
}

287
CCache/test.sh Executable file
View file

@ -0,0 +1,287 @@
#!/bin/sh
# a simple test suite for ccache
# tridge@samba.org
if test -n "$CC"; then
COMPILER="$CC"
else
COMPILER=cc
fi
CCACHE=../ccache
TESTDIR=test.$$
test_failed() {
reason="$1"
echo $1
$CCACHE -s
cd ..
rm -rf $TESTDIR
echo TEST FAILED
exit 1
}
randcode() {
outfile="$1"
nlines=$2
i=0;
(
while [ $i -lt $nlines ]; do
echo "int foo$nlines$i(int x) { return x; }"
i=`expr $i + 1`
done
) >> "$outfile"
}
getstat() {
stat="$1"
value=`$CCACHE -s | grep "$stat" | cut -c34-40`
echo $value
}
checkstat() {
stat="$1"
expected_value="$2"
value=`getstat "$stat"`
if [ "$expected_value" != "$value" ]; then
test_failed "SUITE: $testsuite TEST: $testname - Expected $stat to be $expected_value got $value"
fi
}
basetests() {
echo "starting testsuite $testsuite"
rm -rf .ccache
checkstat 'cache hit' 0
checkstat 'cache miss' 0
j=1
rm -f *.c
while [ $j -lt 32 ]; do
randcode test$j.c $j
j=`expr $j + 1`
done
testname="BASIC"
$CCACHE_COMPILE -c test1.c
checkstat 'cache hit' 0
checkstat 'cache miss' 1
testname="BASIC2"
$CCACHE_COMPILE -c test1.c
checkstat 'cache hit' 1
checkstat 'cache miss' 1
testname="debug"
$CCACHE_COMPILE -c test1.c -g
checkstat 'cache hit' 1
checkstat 'cache miss' 2
testname="debug2"
$CCACHE_COMPILE -c test1.c -g
checkstat 'cache hit' 2
checkstat 'cache miss' 2
testname="output"
$CCACHE_COMPILE -c test1.c -o foo.o
checkstat 'cache hit' 3
checkstat 'cache miss' 2
testname="link"
$CCACHE_COMPILE test1.c -o test 2> /dev/null
checkstat 'called for link' 1
testname="multiple"
$CCACHE_COMPILE -c test1.c test2.c
checkstat 'multiple source files' 1
testname="find"
$CCACHE blahblah -c test1.c 2> /dev/null
checkstat "couldn't find the compiler" 1
testname="bad"
$CCACHE_COMPILE -c test1.c -I 2> /dev/null
checkstat 'bad compiler arguments' 1
testname="c/c++"
ln -f test1.c test1.ccc
$CCACHE_COMPILE -c test1.ccc 2> /dev/null
checkstat 'not a C/C++ file' 1
testname="unsupported"
$CCACHE_COMPILE -M foo -c test1.c > /dev/null 2>&1
checkstat 'unsupported compiler option' 1
testname="stdout"
$CCACHE echo foo -c test1.c > /dev/null
checkstat 'compiler produced stdout' 1
testname="non-regular"
mkdir testd
$CCACHE_COMPILE -o testd -c test1.c > /dev/null 2>&1
rmdir testd
checkstat 'output to a non-regular file' 1
testname="no-input"
$CCACHE_COMPILE -c -O2 2> /dev/null
checkstat 'no input file' 1
testname="CCACHE_DISABLE"
CCACHE_DISABLE=1 $CCACHE_COMPILE -c test1.c 2> /dev/null
checkstat 'cache hit' 3
$CCACHE_COMPILE -c test1.c
checkstat 'cache hit' 4
testname="CCACHE_CPP2"
CCACHE_CPP2=1 $CCACHE_COMPILE -c test1.c -O -O
checkstat 'cache hit' 4
checkstat 'cache miss' 3
CCACHE_CPP2=1 $CCACHE_COMPILE -c test1.c -O -O
checkstat 'cache hit' 5
checkstat 'cache miss' 3
testname="CCACHE_NOSTATS"
CCACHE_NOSTATS=1 $CCACHE_COMPILE -c test1.c -O -O
checkstat 'cache hit' 5
checkstat 'cache miss' 3
testname="CCACHE_RECACHE"
CCACHE_RECACHE=1 $CCACHE_COMPILE -c test1.c -O -O
checkstat 'cache hit' 5
checkstat 'cache miss' 4
# strictly speaking should be 6 - RECACHE causes a double counting!
checkstat 'files in cache' 8
$CCACHE -c > /dev/null
checkstat 'files in cache' 6
testname="CCACHE_HASHDIR"
CCACHE_HASHDIR=1 $CCACHE_COMPILE -c test1.c -O -O
checkstat 'cache hit' 5
checkstat 'cache miss' 5
CCACHE_HASHDIR=1 $CCACHE_COMPILE -c test1.c -O -O
checkstat 'cache hit' 6
checkstat 'cache miss' 5
checkstat 'files in cache' 8
testname="comments"
echo '/* a silly comment */' > test1-comment.c
cat test1.c >> test1-comment.c
$CCACHE_COMPILE -c test1-comment.c
rm -f test1-comment*
checkstat 'cache hit' 6
checkstat 'cache miss' 6
testname="CCACHE_UNIFY"
CCACHE_UNIFY=1 $CCACHE_COMPILE -c test1.c
checkstat 'cache hit' 6
checkstat 'cache miss' 7
mv test1.c test1-saved.c
echo '/* another comment */' > test1.c
cat test1-saved.c >> test1.c
CCACHE_UNIFY=1 $CCACHE_COMPILE -c test1.c
mv test1-saved.c test1.c
checkstat 'cache hit' 7
checkstat 'cache miss' 7
testname="cache-size"
for f in *.c; do
$CCACHE_COMPILE -c $f
done
checkstat 'cache hit' 8
checkstat 'cache miss' 37
checkstat 'files in cache' 72
$CCACHE -F 48 -c > /dev/null
if [ `getstat 'files in cache'` -gt 48 ]; then
test_failed '-F test failed'
fi
testname="cpp call"
$CCACHE_COMPILE -c test1.c -E > test1.i
checkstat 'cache hit' 8
checkstat 'cache miss' 37
testname="direct .i compile"
$CCACHE_COMPILE -c test1.c
checkstat 'cache hit' 8
checkstat 'cache miss' 38
$CCACHE_COMPILE -c test1.i
checkstat 'cache hit' 9
checkstat 'cache miss' 38
$CCACHE_COMPILE -c test1.i
checkstat 'cache hit' 10
checkstat 'cache miss' 38
# removed these tests as some compilers (including newer versions of gcc)
# determine which language to use based on .ii/.i extension, and C++ may
# not be installed
# testname="direct .ii file"
# mv test1.i test1.ii
# $CCACHE_COMPILE -c test1.ii
# checkstat 'cache hit' 10
# checkstat 'cache miss' 39
# $CCACHE_COMPILE -c test1.ii
# checkstat 'cache hit' 11
# checkstat 'cache miss' 39
testname="zero-stats"
$CCACHE -z > /dev/null
checkstat 'cache hit' 0
checkstat 'cache miss' 0
testname="clear"
$CCACHE -C > /dev/null
checkstat 'files in cache' 0
rm -f test1.c
}
######
# main program
rm -rf $TESTDIR
mkdir $TESTDIR
cd $TESTDIR || exit 1
mkdir .ccache
CCACHE_DIR=.ccache
export CCACHE_DIR
testsuite="base"
CCACHE_COMPILE="$CCACHE $COMPILER"
basetests
testsuite="link"
ln -s ../ccache $COMPILER
CCACHE_COMPILE="./$COMPILER"
basetests
testsuite="hardlink"
CCACHE_COMPILE="$CCACHE $COMPILER"
CCACHE_HARDLINK=1 basetests
testsuite="cpp2"
CCACHE_COMPILE="$CCACHE $COMPILER"
CCACHE_CPP2=1 basetests
testsuite="nlevels4"
CCACHE_COMPILE="$CCACHE $COMPILER"
CCACHE_NLEVELS=4 basetests
testsuite="nlevels1"
CCACHE_COMPILE="$CCACHE $COMPILER"
CCACHE_NLEVELS=1 basetests
cd ..
rm -rf $TESTDIR
echo test done - OK
exit 0

269
CCache/unify.c Normal file
View file

@ -0,0 +1,269 @@
/*
Copyright (C) Andrew Tridgell 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
C/C++ unifier
the idea is that changes that don't affect the resulting C code
should not change the hash. This is achieved by folding white-space
and other non-semantic fluff in the input into a single unified format.
This unifier was design to match the output of the unifier in
compilercache, which is flex based. The major difference is that
this unifier is much faster (about 2x) and more forgiving of
syntactic errors. Continuing on syntactic errors is important to
cope with C/C++ extensions in the local compiler (for example,
inline assembly systems).
*/
#include "ccache.h"
static char *s_tokens[] = {
"...", ">>=", "<<=", "+=", "-=", "*=", "/=", "%=", "&=", "^=",
"|=", ">>", "<<", "++", "--", "->", "&&", "||", "<=", ">=",
"==", "!=", ";", "{", "<%", "}", "%>", ",", ":", "=",
"(", ")", "[", "<:", "]", ":>", ".", "&", "!", "~",
"-", "+", "*", "/", "%", "<", ">", "^", "|", "?",
0
};
#define C_ALPHA 1
#define C_SPACE 2
#define C_TOKEN 4
#define C_QUOTE 8
#define C_DIGIT 16
#define C_HEX 32
#define C_FLOAT 64
#define C_SIGN 128
static struct {
unsigned char type;
unsigned char num_toks;
char *toks[7];
} tokens[256];
/* build up the table used by the unifier */
static void build_table(void)
{
unsigned char c;
int i;
static int done;
if (done) return;
done = 1;
memset(tokens, 0, sizeof(tokens));
for (c=0;c<128;c++) {
if (isalpha(c) || c == '_') tokens[c].type |= C_ALPHA;
if (isdigit(c)) tokens[c].type |= C_DIGIT;
if (isspace(c)) tokens[c].type |= C_SPACE;
if (isxdigit(c)) tokens[c].type |= C_HEX;
}
tokens['\''].type |= C_QUOTE;
tokens['"'].type |= C_QUOTE;
tokens['l'].type |= C_FLOAT;
tokens['L'].type |= C_FLOAT;
tokens['f'].type |= C_FLOAT;
tokens['F'].type |= C_FLOAT;
tokens['U'].type |= C_FLOAT;
tokens['u'].type |= C_FLOAT;
tokens['-'].type |= C_SIGN;
tokens['+'].type |= C_SIGN;
for (i=0;s_tokens[i];i++) {
c = s_tokens[i][0];
tokens[c].type |= C_TOKEN;
tokens[c].toks[tokens[c].num_toks] = s_tokens[i];
tokens[c].num_toks++;
}
}
/* buffer up characters before hashing them */
static void pushchar(unsigned char c)
{
static unsigned char buf[64];
static int len;
if (c == 0) {
if (len > 0) {
hash_buffer((char *)buf, len);
len = 0;
}
hash_buffer(NULL, 0);
return;
}
buf[len++] = c;
if (len == 64) {
hash_buffer((char *)buf, len);
len = 0;
}
}
/* hash some C/C++ code after unifying */
static void unify(unsigned char *p, size_t size)
{
size_t ofs;
unsigned char q;
int i;
build_table();
for (ofs=0; ofs<size;) {
if (p[ofs] == '#') {
if ((size-ofs) > 2 && p[ofs+1] == ' ' && isdigit(p[ofs+2])) {
do {
ofs++;
} while (ofs < size && p[ofs] != '\n');
ofs++;
} else {
do {
pushchar(p[ofs]);
ofs++;
} while (ofs < size && p[ofs] != '\n');
pushchar('\n');
ofs++;
}
continue;
}
if (tokens[p[ofs]].type & C_ALPHA) {
do {
pushchar(p[ofs]);
ofs++;
} while (ofs < size &&
(tokens[p[ofs]].type & (C_ALPHA|C_DIGIT)));
pushchar('\n');
continue;
}
if (tokens[p[ofs]].type & C_DIGIT) {
do {
pushchar(p[ofs]);
ofs++;
} while (ofs < size &&
((tokens[p[ofs]].type & C_DIGIT) || p[ofs] == '.'));
if (ofs < size && (p[ofs] == 'x' || p[ofs] == 'X')) {
do {
pushchar(p[ofs]);
ofs++;
} while (ofs < size && (tokens[p[ofs]].type & C_HEX));
}
if (ofs < size && (p[ofs] == 'E' || p[ofs] == 'e')) {
pushchar(p[ofs]);
ofs++;
while (ofs < size &&
(tokens[p[ofs]].type & (C_DIGIT|C_SIGN))) {
pushchar(p[ofs]);
ofs++;
}
}
while (ofs < size && (tokens[p[ofs]].type & C_FLOAT)) {
pushchar(p[ofs]);
ofs++;
}
pushchar('\n');
continue;
}
if (tokens[p[ofs]].type & C_SPACE) {
do {
ofs++;
} while (ofs < size && (tokens[p[ofs]].type & C_SPACE));
continue;
}
if (tokens[p[ofs]].type & C_QUOTE) {
q = p[ofs];
pushchar(p[ofs]);
do {
ofs++;
while (ofs < size-1 && p[ofs] == '\\') {
pushchar(p[ofs]);
pushchar(p[ofs+1]);
ofs+=2;
}
pushchar(p[ofs]);
} while (ofs < size && p[ofs] != q);
pushchar('\n');
ofs++;
continue;
}
if (tokens[p[ofs]].type & C_TOKEN) {
q = p[ofs];
for (i=0;i<tokens[q].num_toks;i++) {
unsigned char *s = (unsigned char *)tokens[q].toks[i];
int len = strlen((char *)s);
if (size >= ofs+len && memcmp(&p[ofs], s, len) == 0) {
int j;
for (j=0;s[j];j++) {
pushchar(s[j]);
ofs++;
}
pushchar('\n');
break;
}
}
if (i < tokens[q].num_toks) {
continue;
}
}
pushchar(p[ofs]);
pushchar('\n');
ofs++;
}
pushchar(0);
}
/* hash a file that consists of preprocessor output, but remove any line
number information from the hash
*/
int unify_hash(const char *fname)
{
int fd;
struct stat st;
char *map;
fd = open(fname, O_RDONLY|O_BINARY);
if (fd == -1 || fstat(fd, &st) != 0) {
cc_log("Failed to open preprocessor output %s\n", fname);
stats_update(STATS_PREPROCESSOR);
return -1;
}
/* we use mmap() to make it easy to handle arbitrarily long
lines in preprocessor output. I have seen lines of over
100k in length, so this is well worth it */
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (map == (char *)-1) {
cc_log("Failed to mmap %s\n", fname);
return -1;
}
close(fd);
/* pass it through the unifier */
unify((unsigned char *)map, st.st_size);
munmap(map, st.st_size);
return 0;
}

454
CCache/util.c Normal file
View file

@ -0,0 +1,454 @@
/*
Copyright (C) Andrew Tridgell 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ccache.h"
static FILE *logfile;
/* log a message to the CCACHE_LOGFILE location */
void cc_log(const char *format, ...)
{
va_list ap;
extern char *cache_logfile;
if (!cache_logfile) return;
if (!logfile) logfile = fopen(cache_logfile, "a");
if (!logfile) return;
va_start(ap, format);
vfprintf(logfile, format, ap);
va_end(ap);
fflush(logfile);
}
/* something went badly wrong! */
void fatal(const char *msg)
{
cc_log("FATAL: %s\n", msg);
exit(1);
}
/* copy all data from one file descriptor to another */
void copy_fd(int fd_in, int fd_out)
{
char buf[10240];
int n;
while ((n = read(fd_in, buf, sizeof(buf))) > 0) {
if (write(fd_out, buf, n) != n) {
fatal("Failed to copy fd");
}
}
}
/* copy a file - used when hard links don't work
the copy is done via a temporary file and atomic rename
*/
int copy_file(const char *src, const char *dest)
{
int fd1, fd2;
char buf[10240];
int n;
char *tmp_name;
mode_t mask;
x_asprintf(&tmp_name, "%s.XXXXXX", dest);
fd1 = open(src, O_RDONLY|O_BINARY);
if (fd1 == -1) {
free(tmp_name);
return -1;
}
fd2 = mkstemp(tmp_name);
if (fd2 == -1) {
close(fd1);
free(tmp_name);
return -1;
}
while ((n = read(fd1, buf, sizeof(buf))) > 0) {
if (write(fd2, buf, n) != n) {
close(fd2);
close(fd1);
unlink(tmp_name);
free(tmp_name);
return -1;
}
}
close(fd1);
/* get perms right on the tmp file */
mask = umask(0);
fchmod(fd2, 0666 & ~mask);
umask(mask);
/* the close can fail on NFS if out of space */
if (close(fd2) == -1) {
unlink(tmp_name);
free(tmp_name);
return -1;
}
unlink(dest);
if (rename(tmp_name, dest) == -1) {
unlink(tmp_name);
free(tmp_name);
return -1;
}
free(tmp_name);
return 0;
}
/* make sure a directory exists */
int create_dir(const char *dir)
{
struct stat st;
if (stat(dir, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
return 0;
}
errno = ENOTDIR;
return 1;
}
if (mkdir(dir, 0777) != 0 && errno != EEXIST) {
return 1;
}
return 0;
}
/*
this is like asprintf() but dies if the malloc fails
note that we use vsnprintf in a rather poor way to make this more portable
*/
void x_asprintf(char **ptr, const char *format, ...)
{
va_list ap;
*ptr = NULL;
va_start(ap, format);
vasprintf(ptr, format, ap);
va_end(ap);
if (!ptr) fatal("out of memory in x_asprintf");
}
/*
this is like strdup() but dies if the malloc fails
*/
char *x_strdup(const char *s)
{
char *ret;
ret = strdup(s);
if (!ret) {
fatal("out of memory in strdup\n");
}
return ret;
}
/*
this is like malloc() but dies if the malloc fails
*/
void *x_malloc(size_t size)
{
void *ret;
ret = malloc(size);
if (!ret) {
fatal("out of memory in malloc\n");
}
return ret;
}
/*
this is like realloc() but dies if the malloc fails
*/
void *x_realloc(void *ptr, size_t size)
{
void *p2;
if (!ptr) return x_malloc(size);
p2 = malloc(size);
if (!p2) {
fatal("out of memory in x_realloc");
}
if (ptr) {
memcpy(p2, ptr, size);
free(ptr);
}
return p2;
}
/*
revsusive directory traversal - used for cleanup
fn() is called on all files/dirs in the tree
*/
void traverse(const char *dir, void (*fn)(const char *, struct stat *))
{
DIR *d;
struct dirent *de;
d = opendir(dir);
if (!d) return;
while ((de = readdir(d))) {
char *fname;
struct stat st;
if (strcmp(de->d_name,".") == 0) continue;
if (strcmp(de->d_name,"..") == 0) continue;
if (strlen(de->d_name) == 0) continue;
x_asprintf(&fname, "%s/%s", dir, de->d_name);
if (lstat(fname, &st)) {
if (errno != ENOENT) {
perror(fname);
}
free(fname);
continue;
}
if (S_ISDIR(st.st_mode)) {
traverse(fname, fn);
}
fn(fname, &st);
free(fname);
}
closedir(d);
}
/* return the base name of a file - caller frees */
char *str_basename(const char *s)
{
char *p = strrchr(s, '/');
if (p) {
return x_strdup(p+1);
}
return x_strdup(s);
}
/* return the dir name of a file - caller frees */
char *dirname(char *s)
{
char *p;
s = x_strdup(s);
p = strrchr(s, '/');
if (p) {
*p = 0;
}
return s;
}
int lock_fd(int fd)
{
struct flock fl;
int ret;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
fl.l_pid = 0;
/* not sure why we would be getting a signal here,
but one user claimed it is possible */
do {
ret = fcntl(fd, F_SETLKW, &fl);
} while (ret == -1 && errno == EINTR);
return ret;
}
/* return size on disk of a file */
size_t file_size(struct stat *st)
{
size_t size = st->st_blocks * 512;
if ((size_t)st->st_size > size) {
/* probably a broken stat() call ... */
size = (st->st_size + 1023) & ~1023;
}
return size;
}
/* a safe open/create for read-write */
int safe_open(const char *fname)
{
int fd = open(fname, O_RDWR|O_BINARY);
if (fd == -1 && errno == ENOENT) {
fd = open(fname, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0666);
if (fd == -1 && errno == EEXIST) {
fd = open(fname, O_RDWR|O_BINARY);
}
}
return fd;
}
/* display a kilobyte unsigned value in M, k or G */
void display_size(unsigned v)
{
if (v > 1024*1024) {
printf("%8.1f Gbytes", v/((double)(1024*1024)));
} else if (v > 1024) {
printf("%8.1f Mbytes", v/((double)(1024)));
} else {
printf("%8u Kbytes", v);
}
}
/* return a value in multiples of 1024 give a string that can end
in K, M or G
*/
size_t value_units(const char *s)
{
char m;
double v = atof(s);
m = s[strlen(s)-1];
switch (m) {
case 'G':
case 'g':
default:
v *= 1024*1024;
break;
case 'M':
case 'm':
v *= 1024;
break;
case 'K':
case 'k':
v *= 1;
break;
}
return (size_t)v;
}
/*
a sane realpath() function, trying to cope with stupid path limits and
a broken API
*/
char *x_realpath(const char *path)
{
int maxlen;
char *ret, *p;
#ifdef PATH_MAX
maxlen = PATH_MAX;
#elif defined(MAXPATHLEN)
maxlen = MAXPATHLEN;
#elif defined(_PC_PATH_MAX)
maxlen = pathconf(path, _PC_PATH_MAX);
#endif
if (maxlen < 4096) maxlen = 4096;
ret = x_malloc(maxlen);
#if HAVE_REALPATH
p = realpath(path, ret);
#else
/* yes, there are such systems. This replacement relies on
the fact that when we call x_realpath we only care about symlinks */
{
int len = readlink(path, ret, maxlen-1);
if (len == -1) {
free(ret);
return NULL;
}
ret[len] = 0;
p = ret;
}
#endif
if (p) {
p = x_strdup(p);
free(ret);
return p;
}
free(ret);
return NULL;
}
/* a getcwd that will returns an allocated buffer */
char *gnu_getcwd(void)
{
unsigned size = 128;
while (1) {
char *buffer = (char *)x_malloc(size);
if (getcwd(buffer, size) == buffer) {
return buffer;
}
free(buffer);
if (errno != ERANGE) {
return 0;
}
size *= 2;
}
}
#ifndef HAVE_MKSTEMP
/* cheap and nasty mkstemp replacement */
int mkstemp(char *template)
{
mktemp(template);
return open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
}
#endif
/* create an empty file */
int create_empty_file(const char *fname)
{
int fd;
fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
if (fd == -1) {
return -1;
}
close(fd);
return 0;
}
/*
return current users home directory or die
*/
const char *get_home_directory(void)
{
const char *p = getenv("HOME");
if (p) {
return p;
}
#ifdef HAVE_GETPWUID
{
struct passwd *pwd = getpwuid(getuid());
if (pwd) {
return pwd->pw_dir;
}
}
#endif
fatal("Unable to determine home directory");
return NULL;
}

318
CCache/web/ccache-man.html Normal file
View file

@ -0,0 +1,318 @@
<html><head><title>ccache</title>
<link rev="made" href="mailto:bugs@ccache.samba.org">
</head>
<body>
<hr>
<h1>ccache</h1>
<h2>April 2002</h2>
<h2>NAME</h2>
ccache - a fast compiler cache
<h2>SYNOPSIS</h2>
<p>ccache [OPTION]
<p>ccache &lt;compiler&gt; [COMPILER OPTIONS]
<p>&lt;compiler&gt; [COMPILER OPTIONS]
<p><h2>DESCRIPTION</h2>
<p>ccache is a compiler cache. It speeds up re-compilation of C/C++ code
by caching previous compiles and detecting when the same compile is
being done again.
<p><h2>OPTIONS SUMMARY</h2>
<p>Here is a summary of the options to ccache.
<p><pre>
-s show statistics summary
-z zero statistics
-c run a cache cleanup
-C clear the cache completely
-F &lt;maxfiles&gt; set maximum files in cache
-M &lt;maxsize&gt; set maximum size of cache (use G, M or K)
-h this help page
-V print version number
</pre>
<p><h2>OPTIONS</h2>
<p>These options only apply when you invoke ccache as "ccache". When
invoked as a compiler none of these options apply. In that case your
normal compiler options apply and you should refer to your compilers
documentation.
<p><dl>
<p></p><dt><strong><strong>-h</strong></strong><dd> Print a options summary page
<p><p></p><dt><strong><strong>-s</strong></strong><dd> Print the current statistics summary for the cache. The
statistics are stored spread across the subdirectories of the
cache. Using "ccache -s" adds up the statistics across all
subdirectories and prints the totals.
<p><p></p><dt><strong><strong>-z</strong></strong><dd> Zero the cache statistics.
<p><p></p><dt><strong><strong>-V</strong></strong><dd> Print the ccache version number
<p><p></p><dt><strong><strong>-c</strong></strong><dd> Clean the cache and re-calculate the cache file count and
size totals. Normally the -c option should not be necessary as ccache
keeps the cache below the specified limits at runtime and keeps
statistics up to date on each compile. This option is mostly useful
if you manually modify the cache contents or believe that the cache
size statistics may be inaccurate.
<p><p></p><dt><strong><strong>-C</strong></strong><dd> Clear the entire cache, removing all cached files.
<p><p></p><dt><strong><strong>-F maxfiles</strong></strong><dd> This sets the maximum number of files allowed in
the cache. The value is stored inside the cache directory and applies
to all future compiles. Due to the way the value is stored the actual
value used is always rounded down to the nearest multiple of 16.
<p><p></p><dt><strong><strong>-M maxsize</strong></strong><dd> This sets the maximum cache size. You can specify
a value in gigabytes, megabytes or kilobytes by appending a G, M or K
to the value. The default is gigabytes. The actual value stored is
rounded down to the nearest multiple of 16 kilobytes.
<p></dl>
<p><h2>INSTALLATION</h2>
<p>There are two ways to use ccache. You can either prefix your compile
commands with "ccache" or you can create a symbolic link between
ccache and the names of your compilers. The first method is most
convenient if you just want to try out ccache or wish to use it for
some specific projects. The second method is most useful for when you
wish to use ccache for all your compiles.
<p>To install for usage by the first method just copy ccache to somewhere
in your path.
<p>To install for the second method do something like this:
<pre>
cp ccache /usr/local/bin/
ln -s /usr/local/bin/ccache /usr/local/bin/gcc
ln -s /usr/local/bin/ccache /usr/local/bin/g++
ln -s /usr/local/bin/ccache /usr/local/bin/cc
</pre>
This will work as long as /usr/local/bin comes before the path to gcc
(which is usually in /usr/bin). After installing you may wish to run
"which gcc" to make sure that the correct link is being used.
<p>Note! Do not use a hard link, use a symbolic link. A hardlink will
cause "interesting" problems.
<p><h2>EXTRA OPTIONS</h2>
<p>When run as a compiler front end ccache usually just takes the same
command line options as the compiler you are using. The only exception
to this is the option '--ccache-skip'. That option can be used to tell
ccache that the next option is definitely not a input filename, and
should be passed along to the compiler as-is.
<p>The reason this can be important is that ccache does need to parse the
command line and determine what is an input filename and what is a
compiler option, as it needs the input filename to determine the name
of the resulting object file (among other things). The heuristic
ccache uses in this parse is that any string on the command line that
exists as a file is treated as an input file name (usually a C
file). By using --ccache-skip you can force an option to not be
treated as an input file name and instead be passed along to the
compiler as a command line option.
<p><h2>ENVIRONMENT VARIABLES</h2>
<p>ccache uses a number of environment variables to control operation. In
most cases you won't need any of these as the defaults will be fine.
<p><dl>
<p><p></p><dt><strong><strong>CCACHE_DIR</strong></strong><dd> the CCACHE_DIR environment variable specifies
where ccache will keep its cached compiler output. The default is
"$HOME/.ccache".
<p><p></p><dt><strong><strong>CCACHE_TEMPDIR</strong></strong><dd> the CCACHE_TEMPDIR environment variable specifies
where ccache will put temporary files. The default is the same as
CCACHE_DIR. Note that the CCACHE_TEMPDIR path must be on the same
filesystem as the CCACHE_DIR path, so that renames of files between
the two directories can work.
<p><p></p><dt><strong><strong>CCACHE_LOGFILE</strong></strong><dd> If you set the CCACHE_LOGFILE environment
variable then ccache will write some log information on cache hits
and misses in that file. This is useful for tracking down problems.
<p><p></p><dt><strong><strong>CCACHE_PATH</strong></strong><dd> You can optionally set CCACHE_PATH to a colon
separated path where ccache will look for the real compilers. If you
don't do this then ccache will look for the first executable matching
the compiler name in the normal PATH that isn't a symbolic link to
ccache itself.
<p><p></p><dt><strong><strong>CCACHE_CC</strong></strong><dd> You can optionally set CCACHE_CC to force the name
of the compiler to use. If you don't do this then ccache works it out
from the command line.
<p><p></p><dt><strong><strong>CCACHE_PREFIX</strong></strong><dd> This option adds a prefix to the command line
that ccache runs when invoking the compiler. Also see the section
below on using ccache with distcc.
<p><p></p><dt><strong><strong>CCACHE_DISABLE</strong></strong><dd> If you set the environment variable
CCACHE_DISABLE then ccache will just call the real compiler,
bypassing the cache completely.
<p><p></p><dt><strong><strong>CCACHE_READONLY</strong></strong><dd> the CCACHE_READONLY environment variable
tells ccache to attempt to use existing cached object files, but not
to try to add anything new to the cache. If you are using this because
your CCACHE_DIR is read-only, then you may find that you also need to
set CCACHE_TEMPDIR as otherwise ccache will fail to create the
temporary files.
<p><p></p><dt><strong><strong>CCACHE_CPP2</strong></strong><dd> If you set the environment variable CCACHE_CPP2
then ccache will not use the optimisation of avoiding the 2nd call to
the pre-processor by compiling the pre-processed output that was used
for finding the hash in the case of a cache miss. This is primarily a
debugging option, although it is possible that some unusual compilers
will have problems with the intermediate filename extensions used in
this optimisation, in which case this option could allow ccache to be
used.
<p><p></p><dt><strong><strong>CCACHE_NOSTATS</strong></strong><dd> If you set the environment variable
CCACHE_NOSTATS then ccache will not update the statistics files on
each compile.
<p><p></p><dt><strong><strong>CCACHE_NLEVELS</strong></strong><dd> The environment variable CCACHE_NLEVELS allows
you to choose the number of levels of hash in the cache directory. The
default is 2. The minimum is 1 and the maximum is 8.
<p><p></p><dt><strong><strong>CCACHE_HARDLINK</strong></strong><dd> If you set the environment variable
CCACHE_HARDLINK then ccache will attempt to use hard links from the
cache directory when creating the compiler output rather than using a
file copy. Using hard links is faster, but can confuse programs like
'make' that rely on modification times.
<p><p></p><dt><strong><strong>CCACHE_RECACHE</strong></strong><dd> This forces ccache to not use any cached
results, even if it finds them. New results are still cached, but
existing cache entries are ignored.
<p><p></p><dt><strong><strong>CCACHE_UMASK</strong></strong><dd> This sets the umask for ccache and all child
processes (such as the compiler). This is mostly useful when you wish
to share your cache with other users. Note that this also affects the
file permissions set on the object files created from your
compilations.
<p><p></p><dt><strong><strong>CCACHE_HASHDIR</strong></strong><dd> This tells ccache to hash the current working
directory when calculating the hash that is used to distinguish two
compiles. This prevents a problem with the storage of the current
working directory in the debug info of a object file, which can lead
ccache to give a cached object file that has the working directory in
the debug info set incorrectly. This option is off by default as the
incorrect setting of this debug info rarely causes problems. If you
strike problems with gdb not using the correct directory then enable
this option.
<p><p></p><dt><strong><strong>CCACHE_UNIFY</strong></strong><dd> If you set the environment variable CCACHE_UNIFY
then ccache will use the C/C++ unifier when hashing the pre-processor
output if -g is not used in the compile. The unifier is slower than a
normal hash, so setting this environment variable loses a little bit
of speed, but it means that ccache can take advantage of not
recompiling when the changes to the source code consist of
reformatting only. Note that using CCACHE_UNIFY changes the hash, so
cached compiles with CCACHE_UNIFY set cannot be used when
CCACHE_UNIFY is not set and vice versa. The reason the unifier is off
by default is that it can give incorrect line number information in
compiler warning messages.
<p><p></p><dt><strong><strong>CCACHE_EXTENSION</strong></strong><dd> Normally ccache tries to automatically
determine the extension to use for intermediate C pre-processor files
based on the type of file being compiled. Unfortunately this sometimes
doesn't work, for example when using the aCC compiler on HP-UX. On
systems like this you can use the CCACHE_EXTENSION option to override
the default. On HP-UX set this environment variable to "i" if you use
the aCC compiler.
<p></dl>
<p><h2>CACHE SIZE MANAGEMENT</h2>
<p>By default ccache has a one gigabyte limit on the cache size and no
maximum number of files. You can set a different limit using the
"ccache -M" and "ccache -F" options, which set the size and number of
files limits.
<p>When these limits are reached ccache will reduce the cache to 20%
below the numbers you specified in order to avoid doing the cache
clean operation too often.
<p><h2>HOW IT WORKS</h2>
<p>The basic idea is to detect when you are compiling exactly the same
code a 2nd time and use the previously compiled output. You detect
that it is the same code by forming a hash of:
<p><ul>
<li > the pre-processor output from running the compiler with -E
<li > the command line options
<li > the real compilers size and modification time
<li > any stderr output generated by the compiler
</ul>
<p>These are hashed using md4 (a strong hash) and a cache file is formed
based on that hash result. When the same compilation is done a second
time ccache is able to supply the correct compiler output (including
all warnings etc) from the cache.
<p>ccache has been carefully written to always produce exactly the same
compiler output that you would get without the cache. If you ever
discover a case where ccache changes the output of your compiler then
please let me know.
<p><h2>USING CCACHE WITH DISTCC</h2>
<p>distcc is a very useful program for distributing compilation across a
range of compiler servers. It is often useful to combine distcc with
ccache, so that compiles that are done are sped up by distcc, but that
ccache avoids the compile completely where possible.
<p>To use distcc with ccache I recommend using the CCACHE_PREFIX
option. You just need to set the environment variable CCACHE_PREFIX to
'distcc' and ccache will prefix the command line used with the
compiler with the command 'distcc'.
<p><h2>SHARING A CACHE</h2>
<p>A group of developers can increase the cache hit rate by sharing a
cache directory. The hard links however cause unwanted side effects,
as all links to a cached file share the file's modification timestamp.
This results in false dependencies to be triggered by timestamp-based
build systems whenever another user links to an existing
file. Typically, users will see that their libraries and binaries are
relinked without reason. To share a cache without side effects, the
following conditions need to be met:
<p><ul>
<li > Use the same <strong>CCACHE_DIR</strong> environment variable setting
<li > Set the <strong>CCACHE_NOLINK</strong> environment variable
<li > Make sure everyone sets the CCACHE_UMASK environment variable
to 002, this ensures that cached files are accessible to everyone in
the group.
<li > Make sure that all users have write permission in the entire
cache directory (and that you trust all users of the shared cache).
<li > Make sure that the setgid bit is set on all directories in the
cache. This tells the filesystem to inherit group ownership for new
directories. The command "chmod g+s `find $CCACHE_DIR -type d`" might
be useful for this.
</ul>
<p><h2>HISTORY</h2>
<p>ccache was inspired by the compilercache shell script script written
by Erik Thiele and I would like to thank him for an excellent piece of
work. See
<a href="http://www.erikyyy.de/compilercache/">http://www.erikyyy.de/compilercache/</a>
for the Erik's scripts.
<p>I wrote ccache because I wanted to get a bit more speed out of a
compiler cache and I wanted to remove some of the limitations of the
shell-script version.
<p><h2>DIFFERENCES FROM COMPILERCACHE</h2>
<p>The biggest differences between Erik's compilercache script and ccache
are:
<ul>
<li > ccache is written in C, which makes it a bit faster (calling out to
external programs is mostly what slowed down the scripts).
<li > ccache can automatically find the real compiler
<li > ccache keeps statistics on hits/misses
<li > ccache can do automatic cache management
<li > ccache can cache compiler output that includes warnings. In many
cases this gives ccache a much higher cache hit rate.
<li > ccache can handle a much wider ranger of compiler options
<li > ccache avoids a double call to cpp on a cache miss
</ul>
<p><h2>BUGS</h2>
<p>When the cache is stored on an NFS filesystem, the filesystem must be
exported with the <strong>no_subtree_check</strong> option to make renames between
directories reliable.
<p><h2>CREDITS</h2>
<p>Thanks to the following people for their contributions to ccache
<ul>
<li > Erik Thiele for the original compilercache script
<li > Luciano Rocha for the idea of compiling the pre-processor output
to avoid a 2nd cpp pass
<li > Paul Russell for many suggestions and the debian packaging
</ul>
<p><h2>AUTHOR</h2>
<p>ccache was written by Andrew Tridgell
<a href="http://samba.org/~tridge/">http://samba.org/~tridge/</a>
<p>If you wish to report a problem or make a suggestion then please email
bugs@ccache.samba.org
<p>ccache is released under the GNU General Public License version 2 or
later. Please see the file COPYING for license details.
</body>
</html>

158
CCache/web/index.html Normal file
View file

@ -0,0 +1,158 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<TITLE>ccache</TITLE>
</HEAD>
<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555" ALINK="#cc0033">
<h2>ccache</h2>
ccache is a compiler cache. It acts as a caching pre-processor to
C/C++ compilers, using the -E compiler switch and a hash to detect
when a compilation can be satisfied from cache. This often results in
a 5 to 10 times speedup in common compilations.<p>
The idea came from Erik Thiele wrote the original <a
href="http://compilercache.sourceforge.net/">compilercache</a> program
as a bourne shell script. ccache is a re-implementation of Erik's idea
in C with more features and better performance.<p>
<h2>Latest release</h2>
The latest release is ccache 2.4.
<ul>
<li>Added CCACHE_READONLY option
<li>Added CCACHE_TEMPDIR option
<li>fixed handling of hard-linked compilers on AIX
<li>added O_BINARY support, to try and support win32 compiles
<li>show cache directory in stats output
<li>fixed handling of HOME environment variable
</ul>
See the <a href="/ccache/ccache-man.html">manual page</a> for details
on the new options.<p>
You can get this release from the <a href="/ftp/ccache/">download directory</a>
<p>NOTE! This release changes the hash input slighly, so you will
probably find that you will not get any hits against your existing
cache when you upgrade.
<h2>Why bother?</h2>
Why bother with a compiler cache? If you ever run "make clean; make"
then you can probably benefit from ccache. It is very common for
developers to do a clean build of a project for a whole host of
reasons, and this throws away all the information from your previous
compiles.<p>
By using ccache you can get exactly the same effect as "make clean;
make" but much faster. It also helps a lot when doing RPM builds,
as RPM can make doing incremental builds tricky.<p>
I put the effort into writing ccache for 2 reasons. The first is the
Samba build farm
(<a href="http://build.samba.org/">http://build.samba.org/</a>)
which constantly does clean builds of Samba on about 30 machines after each
CVS commit. On some of those machines the build took over an hour. By
using ccache we get the same effect as clean builds but about 6 times
faster.<p>
The second reason is the autobuild system I used to run for
Quantum. That system builds our whole Linux based OS from scratch
after every CVS commit to catch compilation problems quickly. Using
ccache those builds are much faster.
<h2>Is it safe?</h2>
Yes. The most important aspect of a compiler cache is to <b>always</b>
produce exactly the same output that the real compiler would
produce. The includes providing exactly the same object files and
exactly the same compiler warnings that would be produced if you use
the real compiler. The only way you should be able to tell that you
are using ccache is the speed.<p>
I have coded ccache very carefully to try to provide these guarantees.
<h2>Features</h2>
<ul>
<li> keeps statistics on hits/misses
<li> automatic cache size management
<li> can cache compiles that generate warnings
<li> easy installation
<li> very low overhead
<li> uses hard links where possible to avoid copies
</ul>
<h2>Documentation</h2>
See the <a href="/ccache/ccache-man.html">manual page</a>
<h2>Performance</h2>
Here are some results for compiling Samba on my Linux laptop. I have
also included the results of using Erik's compilercache program
(version 1.0.10) for comparison.<p>
<table border=1>
<tr><th> </th> <th>&nbsp;&nbsp;&nbsp;&nbsp;ccache</th> <th>&nbsp;compilercache</th> </tr>
<tr><td>normal </td> <td align=right>13m 4s </td><td align=right>13m 4s</td> </tr>
<tr><td>uncached </td> <td align=right>13m 15s </td><td align=right>15m 41s</td> </tr>
<tr><td>cached </td> <td align=right>2m 45s </td><td align=right>4m 26s</td> </tr>
</table>
<h2>How to use it</h2>
You can use ccache in two ways. The first is just to prefix your
compile commands with "ccache". For example, you could change the
"CC=gcc" line in your Makefile to be "CC=ccache gcc".<p>
Alternatively, you can create symbolic links from your compilers name
to ccache. This allows you to use ccache without any changes to your
build system.
<h2>Download</h2>
You can download the latest release from the <a
href="/ftp/ccache/">download directory</a>.<p>
For the bleeding edge, you can fetch ccache via CVS or
rsync. To fetch via cvs use the following command:
<pre>
cvs -d :pserver:cvs@pserver.samba.org:/cvsroot co ccache
</pre>
To fetch via rsync use this command:
<pre>
rsync -Pavz samba.org::ftp/unpacked/ccache .
</pre>
<h2>Related projects</h2>
Here are some related programs you may find interesting
<ul>
<li> <a href="http://distcc.samba.org/">distcc</a> - a distributed compilation system
<li> <a href="http://cachecc1.sourceforge.net/">cachecc1</a> - a gcc specific cache
<li> <a href="http://sourceforge.net/projects/gocache/">gocache</a> - a cross platform compiler cache
</ul>
<p>
<h2>Mailing list</h2>
<p>A <a href="http://lists.samba.org/mailman/listinfo/ccache/">mailing
list</a> is available for discussion of ccache.
<hr>
<tiny>
<a href="http://samba.org/~tridge/">Andrew Tridgell</a><br>
<a href="mailto:bugs@ccache.samba.org">bugs@ccache.samba.org</a>
</tiny>
</BODY>
</HTML>