Imported Upstream version 3.2.2 upstream/3.2.2
authorJinWang An <jinwang.an@samsung.com>
Tue, 3 Aug 2021 07:16:40 +0000 (16:16 +0900)
committerJinWang An <jinwang.an@samsung.com>
Tue, 3 Aug 2021 07:16:40 +0000 (16:16 +0900)
30 files changed:
AUTHORS.html
AUTHORS.txt
INSTALL.html
LICENSE.html
LICENSE.txt
MANUAL.html
MANUAL.txt
NEWS.html
NEWS.txt
README.html
ccache.1
ccache.c
ccache.h
cleanup.c
compopt.c
configure
configure.ac
confitems_lookup.c
dev.mk.in
envtoconfitems_lookup.c
execute.c
hash.c
hashutil.c
lockfile.c
manifest.c
stats.c
test.sh
test/test_compopt.c
util.c
version.c

index f6931c23b2b56f017e335360aa856463d67c812b..5c61970fc55cc79e186efcc98ba587e8d50196c6 100644 (file)
@@ -734,7 +734,7 @@ asciidoc.install(2);
 <body class="article">\r
 <div id="header">\r
 <h1>ccache authors</h1>\r
-<span id="revnumber">version 3.2.1</span>\r
+<span id="revnumber">version 3.2.2</span>\r
 <div id="toc">
   <div id="toctitle">Table of Contents</div>
   <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
@@ -754,6 +754,11 @@ Alfred Landrum &lt;<a href="mailto:alfred.landrum@riverbed.com">alfred.landrum@r
 </li>\r
 <li>\r
 <p>\r
+Anders Björklund &lt;<a href="mailto:anders@itension.se">anders@itension.se</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Andrea Bittau &lt;<a href="mailto:a.bittau@cs.ucl.ac.uk">a.bittau@cs.ucl.ac.uk</a>&gt;\r
 </p>\r
 </li>\r
@@ -789,6 +794,11 @@ Bo Rydberg &lt;<a href="mailto:bolry@hotmail.com">bolry@hotmail.com</a>&gt;
 </li>\r
 <li>\r
 <p>\r
+Chiaki ISHIKAWA &lt;<a href="mailto:ishikawa@yk.rim.or.jp">ishikawa@yk.rim.or.jp</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Chris AtLee &lt;<a href="mailto:chris@atlee.ca">chris@atlee.ca</a>&gt;\r
 </p>\r
 </li>\r
@@ -819,6 +829,11 @@ Hongli Lai &lt;<a href="mailto:hongli@phusion.nl">hongli@phusion.nl</a>&gt;
 </li>\r
 <li>\r
 <p>\r
+Jiang Jiang &lt;<a href="mailto:jiangj@opera.com">jiangj@opera.com</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Joel Rosdahl &lt;<a href="mailto:joel@rosdahl.net">joel@rosdahl.net</a>&gt;\r
 </p>\r
 </li>\r
@@ -864,6 +879,11 @@ Lars Gustäbel &lt;<a href="mailto:lars@gustaebel.de">lars@gustaebel.de</a>&gt;
 </li>\r
 <li>\r
 <p>\r
+Leanid Chaika &lt;<a href="mailto:leanid.chaika@gmail.com">leanid.chaika@gmail.com</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Luboš Luňák &lt;<a href="mailto:l.lunak@suse.cz">l.lunak@suse.cz</a>&gt;\r
 </p>\r
 </li>\r
@@ -924,6 +944,11 @@ Robin H. Johnson &lt;<a href="mailto:robbat2@gentoo.org">robbat2@gentoo.org</a>&
 </li>\r
 <li>\r
 <p>\r
+Ryb &lt;<a href="mailto:ryb@ableton.com">ryb@ableton.com</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Tim Potter &lt;<a href="mailto:tpot@samba.org">tpot@samba.org</a>&gt;\r
 </p>\r
 </li>\r
@@ -960,8 +985,9 @@ Yiding Jia &lt;<a href="mailto:yiding@fb.com">yiding@fb.com</a>&gt;
 <div id="footnotes"><hr /></div>\r
 <div id="footer">\r
 <div id="footer-text">\r
-Version 3.2.1<br />\r
-Last updated 2014-12-09 21:16:57 CET\r
+Version 3.2.2<br />\r
+Last updated\r
+ 2015-05-10 14:23:01 CEST\r
 </div>\r
 </div>\r
 </body>\r
index 391000b38b55591a69efcdb2092f1a1d05d0c238..5484fe71e61833b37620947fcfdb38bc114d0f77 100644 (file)
@@ -7,6 +7,7 @@ maintained by Joel Rosdahl.
 ccache is a collective work with contributions from many people, including:
 
 * Alfred Landrum <alfred.landrum@riverbed.com>
+* Anders Björklund <anders@itension.se>
 * Andrea Bittau <a.bittau@cs.ucl.ac.uk>
 * Andrew P Boie <andrew.p.boie@intel.com>
 * Andrew Stubbs <ams@codesourcery.com>
@@ -14,12 +15,14 @@ ccache is a collective work with contributions from many people, including:
 * Bernhard Bauer <bauerb@chromium.org>
 * Björn Jacke <bj@sernet.de>
 * Bo Rydberg <bolry@hotmail.com>
+* Chiaki ISHIKAWA <ishikawa@yk.rim.or.jp>
 * Chris AtLee <chris@atlee.ca>
 * Clemens Rabe <crabe@gmx.de>
 * David Givone <david@givone.net>
 * Eric Blau <Eric.Blau@tekelec.com>
 * Francois Marier <francois@debian.org>
 * Hongli Lai <hongli@phusion.nl>
+* Jiang Jiang <jiangj@opera.com>
 * Joel Rosdahl <joel@rosdahl.net>
 * John Coiner <john.coiner@amd.com>
 * Jon Bernard <jbernard@tuxion.com>
@@ -29,6 +32,7 @@ ccache is a collective work with contributions from many people, including:
 * Kovarththanan Rajaratnam <kovarththanan.rajaratnam@gmail.com>
 * Lalit Chhabra <lchhabra@linuxmail.org>
 * Lars Gustäbel <lars@gustaebel.de>
+* Leanid Chaika <leanid.chaika@gmail.com>
 * Luboš Luňák <l.lunak@suse.cz>
 * Mark Starovoytov <starovoytov.mark@googlemail.com>
 * Martin Pool <mbp@sourcefrog.net>
@@ -41,6 +45,7 @@ ccache is a collective work with contributions from many people, including:
 * RW <fbsd06@mlists.homeunix.com>
 * Ramiro Polla <ramiro.polla@gmail.com>
 * Robin H. Johnson <robbat2@gentoo.org>
+* Ryb <ryb@ableton.com>
 * Tim Potter <tpot@samba.org>
 * Tor Arne Vestbø <torarnv@gmail.com>
 * Ville Skyttä <ville.skytta@iki.fi>
index 734cbc4392c5679c317b93e642ba62be018a63da..1a55552ab224851bb790ca3d2aa16ea26caae0bf 100644 (file)
@@ -734,7 +734,7 @@ asciidoc.install(2);
 <body class="article">\r
 <div id="header">\r
 <h1>ccache installation</h1>\r
-<span id="revnumber">version 3.2.1</span>\r
+<span id="revnumber">version 3.2.2</span>\r
 <div id="toc">
   <div id="toctitle">Table of Contents</div>
   <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
@@ -853,8 +853,9 @@ above.</p></div>
 <div id="footnotes"><hr /></div>\r
 <div id="footer">\r
 <div id="footer-text">\r
-Version 3.2.1<br />\r
-Last updated 2014-12-09 21:16:57 CET\r
+Version 3.2.2<br />\r
+Last updated\r
+ 2015-03-09 20:26:56 CET\r
 </div>\r
 </div>\r
 </body>\r
index 6def0cdc71402bb5fbc4571b995ab8c0acdcf2ef..bb456994ced20232cd8216aa4d3afbb8688c2fcb 100644 (file)
@@ -734,7 +734,7 @@ asciidoc.install(2);
 <body class="article">\r
 <div id="header">\r
 <h1>ccache copyright and license</h1>\r
-<span id="revnumber">version 3.2.1</span>\r
+<span id="revnumber">version 3.2.2</span>\r
 <div id="toc">
   <div id="toctitle">Table of Contents</div>
   <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
@@ -776,7 +776,7 @@ copyrights on their portions of the work.</p></div>
 <div class="listingblock">\r
 <div class="content">\r
 <pre><code>  Copyright (C) 2002-2007 Andrew Tridgell\r
-  Copyright (C) 2009-2011 Joel Rosdahl</code></pre>\r
+  Copyright (C) 2009-2015 Joel Rosdahl</code></pre>\r
 </div></div>\r
 </div>\r
 </div>\r
@@ -1173,11 +1173,11 @@ Appleby. See <a href="http://murmurhash.googlepages.com">http://murmurhash.googl
 </div>\r
 <div class="sect2">\r
 <h3 id="_zlib_hc">zlib/*.[hc]</h3>\r
-<div class="paragraph"><p>This is a bundled subset of zlib 1.2.5 from <a href="http://zlib.net">http://zlib.net</a> with the\r
+<div class="paragraph"><p>This is a bundled subset of zlib 1.2.8 from <a href="http://zlib.net">http://zlib.net</a> with the\r
 following license:</p></div>\r
 <div class="listingblock">\r
 <div class="content">\r
-<pre><code>  Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler\r
+<pre><code>  Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler\r
 \r
   This software is provided 'as-is', without any express or implied\r
   warranty.  In no event will the authors be held liable for any damages\r
@@ -1205,8 +1205,9 @@ following license:</p></div>
 <div id="footnotes"><hr /></div>\r
 <div id="footer">\r
 <div id="footer-text">\r
-Version 3.2.1<br />\r
-Last updated 2014-12-09 21:16:57 CET\r
+Version 3.2.2<br />\r
+Last updated\r
+ 2015-04-19 13:27:37 CEST\r
 </div>\r
 </div>\r
 </body>\r
index 7186d5a41c419be5289f950678a005f67d15a403..5d32ea2774469e8724c834278d951996924ab890 100644 (file)
@@ -38,7 +38,7 @@ The copyright for ccache as a whole is as follows:
 
 -------------------------------------------------------------------------------
   Copyright (C) 2002-2007 Andrew Tridgell
-  Copyright (C) 2009-2011 Joel Rosdahl
+  Copyright (C) 2009-2015 Joel Rosdahl
 -------------------------------------------------------------------------------
 
 
@@ -448,11 +448,11 @@ http://www.jhweiss.de/software/snprintf.html and has the following license:
 zlib/*.[hc]
 ~~~~~~~~~~~
 
-This is a bundled subset of zlib 1.2.5 from <http://zlib.net> with the
+This is a bundled subset of zlib 1.2.8 from <http://zlib.net> with the
 following license:
 
 -------------------------------------------------------------------------------
-  Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+  Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
index 57a922d0ee6a629d34f2aefc592d5b24198064c2..d5bf2f832a05d4f06d0792b7abb57471c946cc2d 100644 (file)
@@ -734,7 +734,7 @@ asciidoc.install(2);
 <body class="article">\r
 <div id="header">\r
 <h1>CCACHE(1)</h1>\r
-<span id="revnumber">version 3.2.1</span>\r
+<span id="revnumber">version 3.2.2</span>\r
 <div id="toc">
   <div id="toctitle">Table of Contents</div>
   <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
@@ -1157,6 +1157,15 @@ setting key. Boolean options are indicated with &#8220;[boolean]&#8221;</p></div
 </p>\r
 </dd>\r
 <dt class="hdlist1">\r
+<strong>string:value</strong>\r
+</dt>\r
+<dd>\r
+<p>\r
+    Use <strong>value</strong> as the string to calculate hash from. This can be the compiler\r
+    revision number you retrieved earlier and set here via environment variable.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
 <em>a command string</em>\r
 </dt>\r
 <dd>\r
@@ -2160,8 +2169,9 @@ maintained by Joel Rosdahl. See AUTHORS.txt or AUTHORS.html and
 <div id="footnotes"><hr /></div>\r
 <div id="footer">\r
 <div id="footer-text">\r
-Version 3.2.1<br />\r
-Last updated 2014-12-09 21:16:57 CET\r
+Version 3.2.2<br />\r
+Last updated\r
+ 2015-04-19 13:27:37 CEST\r
 </div>\r
 </div>\r
 </body>\r
index 4ac113e12154d472934b2f56b8f3df2fba31e60f..d0ee09b8774378280a17157d41a0bf7fcc551a62 100644 (file)
@@ -281,6 +281,9 @@ setting key. Boolean options are indicated with ``[boolean]''
     compiler's source has not changed, or if the compiler only has changes that
     don't affect code generation). You should only use the *none* setting if
     you know what you are doing.
+*string:value*::
+    Use *value* as the string to calculate hash from. This can be the compiler
+    revision number you retrieved earlier and set here via environment variable.
 _a command string_::
     Hash the standard output and standard error output of the specified
     command. The string will be split on whitespace to find out the command and
index 912ecec1a541390bb30b6b6f1aab6fdec2cfd051..af097806c67c334a335e3a495ec259e06c269c3b 100644 (file)
--- a/NEWS.html
+++ b/NEWS.html
@@ -734,7 +734,7 @@ asciidoc.install(2);
 <body class="article">\r
 <div id="header">\r
 <h1>ccache news</h1>\r
-<span id="revnumber">version 3.2.1</span>\r
+<span id="revnumber">version 3.2.2</span>\r
 <div id="toc">
   <div id="toctitle">Table of Contents</div>
   <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
@@ -742,11 +742,105 @@ asciidoc.install(2);
 </div>\r
 <div id="content">\r
 <div class="sect1">\r
+<h2 id="_ccache_3_2_2">ccache 3.2.2</h2>\r
+<div class="sectionbody">\r
+<div class="paragraph"><p>Release date: 2015-05-10</p></div>\r
+<div class="sect2">\r
+<h3 id="_new_features_and_improvements">New features and improvements</h3>\r
+<div class="ulist"><ul>\r
+<li>\r
+<p>\r
+Added support for <code>CCACHE_COMPILERCHECK=string:&lt;value&gt;</code>. This is a faster\r
+  alternative to <code>CCACHE_COMPILERCHECK=&lt;command&gt;</code> if the command&#8217;s output can\r
+  be precalculated by the build system.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Add support for caching code coverage results (compiling for gcov).\r
+</p>\r
+</li>\r
+</ul></div>\r
+</div>\r
+<div class="sect2">\r
+<h3 id="_bug_fixes">Bug fixes</h3>\r
+<div class="ulist"><ul>\r
+<li>\r
+<p>\r
+Fixed bug which could result in false cache hits when source code contains\r
+  <code>'"'</code> followed by <code>" /*"</code> or <code>" //"</code> (with variations).\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Made hash of cached result created with and without <code>CCACHE_CPP2</code> different.\r
+  This makes it possible to rebuild with <code>CCACHE_CPP2</code> set without having to\r
+  clear the cache to get new results.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Don&#8217;t try to reset a non-existing stats file. This avoids &#8220;No such file or\r
+  directory&#8221; messages in the ccache log when the cache directory doesn&#8217;t\r
+  exist.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Fixed a bug where ccache deleted clang diagnostics after compiler failures.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Avoid performing an unnecessary copy of the object file on a cache miss.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Bail out on too hard compiler option <code>-fmodules</code>.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Bail out on too hard compiler option <code>-fplugin=libcc1plugin</code> (interaction\r
+  with GDB).\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Fixed build error when compiling ccache with recent clang versions.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Removed signal-unsafe code from signal handler.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Corrected logic for when to output cached stderr.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Wipe the whole cached result on failure retrieving a cached file.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Fixed build error when compiling ccache with recent clang versions.\r
+</p>\r
+</li>\r
+</ul></div>\r
+</div>\r
+</div>\r
+</div>\r
+<div class="sect1">\r
 <h2 id="_ccache_3_2_1">ccache 3.2.1</h2>\r
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2014-12-10</p></div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes">Bug fixes</h3>\r
+<h3 id="_bug_fixes_2">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -787,7 +881,7 @@ Added missing documentation for <code>max_files</code> and <code>max_size</code>
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2014-11-17</p></div>\r
 <div class="sect2">\r
-<h3 id="_new_features_and_improvements">New features and improvements</h3>\r
+<h3 id="_new_features_and_improvements_2">New features and improvements</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -978,7 +1072,7 @@ Various other improvements of the test suite.
 </ul></div>\r
 </div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_2">Bug fixes</h3>\r
+<h3 id="_bug_fixes_3">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1005,11 +1099,42 @@ Fixed test suite failures when <code>CC</code> is a ccache-wrapped compiler.
 </div>\r
 </div>\r
 <div class="sect1">\r
+<h2 id="_ccache_3_1_11">ccache 3.1.11</h2>\r
+<div class="sectionbody">\r
+<div class="paragraph"><p>Release date: 2015-03-07</p></div>\r
+<div class="sect2">\r
+<h3 id="_bug_fixes_4">Bug fixes</h3>\r
+<div class="ulist"><ul>\r
+<li>\r
+<p>\r
+Fixed bug which could result in false cache hits when source code contains\r
+  <code>'"'</code> followed by <code>" /*"</code> or <code>" //"</code> (with variations).\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Made hash of cached result created with and without <code>CCACHE_CPP2</code> different.\r
+  This makes it possible to rebuild with <code>CCACHE_CPP2</code> set without having to\r
+  clear the cache to get new results.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Don&#8217;t try to reset a non-existing stats file. This avoids &#8220;No such file or\r
+  directory&#8221; messages in the ccache log when the cache directory doesn&#8217;t\r
+  exist.\r
+</p>\r
+</li>\r
+</ul></div>\r
+</div>\r
+</div>\r
+</div>\r
+<div class="sect1">\r
 <h2 id="_ccache_3_1_10">ccache 3.1.10</h2>\r
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2014-10-19</p></div>\r
 <div class="sect2">\r
-<h3 id="_new_features_and_improvements_2">New features and improvements</h3>\r
+<h3 id="_new_features_and_improvements_3">New features and improvements</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1061,7 +1186,7 @@ Stale files in the internal temporary directory (<code>&lt;ccache_dir&gt;/tmp</c
 </ul></div>\r
 </div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_3">Bug fixes</h3>\r
+<h3 id="_bug_fixes_5">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1101,7 +1226,7 @@ Fixed problem with logging of current working directory.
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2013-01-06</p></div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_4">Bug fixes</h3>\r
+<h3 id="_bug_fixes_6">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1151,7 +1276,7 @@ Fixed test suite to work on ecryptfs.
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2012-08-11</p></div>\r
 <div class="sect2">\r
-<h3 id="_new_features_and_improvements_3">New features and improvements</h3>\r
+<h3 id="_new_features_and_improvements_4">New features and improvements</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1172,7 +1297,7 @@ Clang plugins are now hashed to catch plugin upgrades.
 </ul></div>\r
 </div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_5">Bug fixes</h3>\r
+<h3 id="_bug_fixes_7">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1220,7 +1345,7 @@ Fixed <code>static_assert</code> macro definition clash with GCC 4.7.
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2012-01-08</p></div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_6">Bug fixes</h3>\r
+<h3 id="_bug_fixes_8">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1293,7 +1418,7 @@ Improved documentation on how to fix bad object files in the cache.
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2011-08-21</p></div>\r
 <div class="sect2">\r
-<h3 id="_new_features_and_improvements_4">New features and improvements</h3>\r
+<h3 id="_new_features_and_improvements_5">New features and improvements</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1303,7 +1428,7 @@ Rewrite argument to <code>--sysroot</code> if <code>CCACHE_BASEDIR</code> is use
 </ul></div>\r
 </div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_7">Bug fixes</h3>\r
+<h3 id="_bug_fixes_9">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1324,7 +1449,7 @@ Fixed alignment of &#8220;called for preprocessing&#8221; counter.
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2011-05-29</p></div>\r
 <div class="sect2">\r
-<h3 id="_new_features_and_improvements_5">New features and improvements</h3>\r
+<h3 id="_new_features_and_improvements_6">New features and improvements</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1356,7 +1481,7 @@ Improved order of statistics counters in <code>ccache -s</code> output.
 </ul></div>\r
 </div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_8">Bug fixes</h3>\r
+<h3 id="_bug_fixes_10">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1389,7 +1514,7 @@ Systems that lack (and don&#8217;t need to be linked with) libm are now supporte
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2011-01-09</p></div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_9">Bug fixes</h3>\r
+<h3 id="_bug_fixes_11">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1422,7 +1547,7 @@ The file handle in now correctly closed on write error when trying to create
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2010-11-28</p></div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_10">Bug fixes</h3>\r
+<h3 id="_bug_fixes_12">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1449,7 +1574,7 @@ Portability fixes for HP-UX 11.00 and other esoteric systems.
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2010-11-21</p></div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_11">Bug fixes</h3>\r
+<h3 id="_bug_fixes_13">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1497,7 +1622,7 @@ The test suite now also works on systems that lack a /dev/zero.
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2010-11-07</p></div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_12">Bug fixes</h3>\r
+<h3 id="_bug_fixes_14">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1551,7 +1676,7 @@ Minor debug log message improvements.
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2010-09-16</p></div>\r
 <div class="sect2">\r
-<h3 id="_new_features_and_improvements_6">New features and improvements</h3>\r
+<h3 id="_new_features_and_improvements_7">New features and improvements</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1619,7 +1744,7 @@ Added <code>-install_name</code> as an option known to take an argument. (This i
 </ul></div>\r
 </div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_13">Bug fixes</h3>\r
+<h3 id="_bug_fixes_15">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1705,7 +1830,7 @@ New <code>HACKING.txt</code> file with some notes about ccache code conventions.
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2010-07-15</p></div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_14">Bug fixes</h3>\r
+<h3 id="_bug_fixes_16">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1751,7 +1876,7 @@ The way the hashes are calculated has changed, so you won&#8217;t get cache hits
 </ul></div>\r
 </div>\r
 <div class="sect2">\r
-<h3 id="_new_features_and_improvements_7">New features and improvements</h3>\r
+<h3 id="_new_features_and_improvements_8">New features and improvements</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -1894,7 +2019,7 @@ The following options are no longer hashed in the preprocessor mode:
 </ul></div>\r
 </div>\r
 <div class="sect2">\r
-<h3 id="_bug_fixes_15">Bug fixes</h3>\r
+<h3 id="_bug_fixes_17">Bug fixes</h3>\r
 <div class="ulist"><ul>\r
 <li>\r
 <p>\r
@@ -2039,8 +2164,9 @@ Statistics counters are now correctly updated for -E option failures and
 <div id="footnotes"><hr /></div>\r
 <div id="footer">\r
 <div id="footer-text">\r
-Version 3.2.1<br />\r
-Last updated 2014-12-10 20:38:47 CET\r
+Version 3.2.2<br />\r
+Last updated\r
+ 2015-05-10 14:17:58 CEST\r
 </div>\r
 </div>\r
 </body>\r
index ca57aedcef391679adef01e0be15c72a3ebd6b40..4861a4f278917a587b2669df2de733092af0eb8d 100644 (file)
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -2,6 +2,55 @@ ccache news
 ===========
 
 
+ccache 3.2.2
+------------
+Release date: 2015-05-10
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Added support for `CCACHE_COMPILERCHECK=string:<value>`. This is a faster
+  alternative to `CCACHE_COMPILERCHECK=<command>` if the command's output can
+  be precalculated by the build system.
+
+- Add support for caching code coverage results (compiling for gcov).
+
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed bug which could result in false cache hits when source code contains
+  `'"'` followed by `" /*"` or `" //"` (with variations).
+
+- Made hash of cached result created with and without `CCACHE_CPP2` different.
+  This makes it possible to rebuild with `CCACHE_CPP2` set without having to
+  clear the cache to get new results.
+
+- Don't try to reset a non-existing stats file. This avoids ``No such file or
+  directory'' messages in the ccache log when the cache directory doesn't
+  exist.
+
+- Fixed a bug where ccache deleted clang diagnostics after compiler failures.
+
+- Avoid performing an unnecessary copy of the object file on a cache miss.
+
+- Bail out on too hard compiler option `-fmodules`.
+
+- Bail out on too hard compiler option `-fplugin=libcc1plugin` (interaction
+  with GDB).
+
+- Fixed build error when compiling ccache with recent clang versions.
+
+- Removed signal-unsafe code from signal handler.
+
+- Corrected logic for when to output cached stderr.
+
+- Wipe the whole cached result on failure retrieving a cached file.
+
+- Fixed build error when compiling ccache with recent clang versions.
+
+
 ccache 3.2.1
 ------------
 Release date: 2014-12-10
@@ -137,6 +186,26 @@ Bug fixes
 - Fixed test suite failures when `CC` is a ccache-wrapped compiler.
 
 
+ccache 3.1.11
+-------------
+Release date: 2015-03-07
+
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed bug which could result in false cache hits when source code contains
+  `'"'` followed by `" /*"` or `" //"` (with variations).
+
+- Made hash of cached result created with and without `CCACHE_CPP2` different.
+  This makes it possible to rebuild with `CCACHE_CPP2` set without having to
+  clear the cache to get new results.
+
+- Don't try to reset a non-existing stats file. This avoids ``No such file or
+  directory'' messages in the ccache log when the cache directory doesn't
+  exist.
+
+
 ccache 3.1.10
 -------------
 Release date: 2014-10-19
index 6d06405e2315138d6a0de1aaaea328ca14a3fb66..7c5d01fc264b041046e43460a534115feb7913d4 100644 (file)
@@ -734,7 +734,7 @@ asciidoc.install(2);
 <body class="article">\r
 <div id="header">\r
 <h1>ccache README</h1>\r
-<span id="revnumber">version 3.2</span>\r
+<span id="revnumber">version 3.1.11</span>\r
 <div id="toc">
   <div id="toctitle">Table of Contents</div>
   <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
@@ -830,8 +830,9 @@ Thiele&#8217;s &#8220;compilercache&#8221; (see <a href="http://www.erikyyy.de/c
 <div id="footnotes"><hr /></div>\r
 <div id="footer">\r
 <div id="footer-text">\r
-Version 3.2<br />\r
-Last updated 2012-11-07 19:42:42 CET\r
+Version 3.1.11<br />\r
+Last updated\r
+ 2012-11-07 19:42:42 CET\r
 </div>\r
 </div>\r
 </body>\r
index 87abbe90722a6e02953fbd043ce88b0bb0273e81..093d3f0f675307296ae924ab77abebcbe9762b51 100644 (file)
--- a/ccache.1
+++ b/ccache.1
@@ -2,12 +2,12 @@
 .\"     Title: ccache
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 12/10/2014
+.\"      Date: 05/10/2015
 .\"    Manual: ccache Manual
-.\"    Source: ccache 3.2.1
+.\"    Source: ccache 3.2.2
 .\"  Language: English
 .\"
-.TH "CCACHE" "1" "12/10/2014" "ccache 3\&.2\&.1" "ccache Manual"
+.TH "CCACHE" "1" "05/10/2015" "ccache 3\&.2\&.2" "ccache Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -398,6 +398,13 @@ Don\(cqt hash anything\&. This may be good for situations where you can safely u
 setting if you know what you are doing\&.
 .RE
 .PP
+\fBstring:value\fR
+.RS 4
+Use
+\fBvalue\fR
+as the string to calculate hash from\&. This can be the compiler revision number you retrieved earlier and set here via environment variable\&.
+.RE
+.PP
 \fIa command string\fR
 .RS 4
 Hash the standard output and standard error output of the specified command\&. The string will be split on whitespace to find out the command and arguments to run\&. No other interpretation of the command string will be done, except that the special word
index c407760fe87674af5d618e65bd672c690508d139..cb7e72eac9b1f66a251f3d45a82de098393fabd1 100644 (file)
--- a/ccache.c
+++ b/ccache.c
@@ -2,7 +2,7 @@
  * ccache -- a fast C/C++ compiler cache
  *
  * Copyright (C) 2002-2007 Andrew Tridgell
- * Copyright (C) 2009-2014 Joel Rosdahl
+ * Copyright (C) 2009-2015 Joel Rosdahl
  *
  * 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
@@ -39,7 +39,7 @@ static const char VERSION_TEXT[] =
 MYNAME " version %s\n"
 "\n"
 "Copyright (C) 2002-2007 Andrew Tridgell\n"
-"Copyright (C) 2009-2011 Joel Rosdahl\n"
+"Copyright (C) 2009-2015 Joel Rosdahl\n"
 "\n"
 "This program is free software; you can redistribute it and/or modify it under\n"
 "the terms of the GNU General Public License as published by the Free Software\n"
@@ -95,6 +95,9 @@ static char *output_obj;
 /* The path to the dependency file (implicit or specified with -MF). */
 static char *output_dep;
 
+/* The path to the coverage file (implicit when using -ftest-coverage). */
+static char *output_cov;
+
 /* Diagnostic generation information (clang). */
 static char *output_dia = NULL;
 
@@ -122,6 +125,12 @@ static char *cached_stderr;
  */
 static char *cached_dep;
 
+/*
+ * Full path to the file containing the coverage information
+ * (cachedir/a/b/cdef[...]-size.gcno).
+ */
+static char *cached_cov;
+
 /*
  * Full path to the file containing the diagnostic information (for clang)
  * (cachedir/a/b/cdef[...]-size.dia).
@@ -149,6 +158,15 @@ static struct hashtable *included_files;
 /* is gcc being asked to output dependencies? */
 static bool generating_dependencies;
 
+/* is gcc being asked to output coverage? */
+static bool generating_coverage;
+
+/* is gcc being asked to output coverage data (.gcda) at runtime? */
+static bool profile_arcs;
+
+/* name of the custom profile directory (default: object dirname) */
+static char *profile_dir;
+
 /* the name of the temporary pre-processor file */
 static char *i_tmpfile;
 
@@ -188,8 +206,7 @@ unsigned lock_staleness_limit = 2000000;
 
 enum fromcache_call_mode {
        FROMCACHE_DIRECT_MODE,
-       FROMCACHE_CPP_MODE,
-       FROMCACHE_COMPILED_MODE
+       FROMCACHE_CPP_MODE
 };
 
 struct pending_tmp_file {
@@ -289,7 +306,8 @@ clean_up_pending_tmp_files(void)
 {
        struct pending_tmp_file *p = pending_tmp_files;
        while (p) {
-               tmp_unlink(p->path);
+               /* Can't call tmp_unlink here since its cc_log calls aren't signal safe. */
+               unlink(p->path);
                p = p->next;
                /* Leak p->path and p here because clean_up_pending_tmp_files needs to be
                 * signal safe. */
@@ -311,8 +329,7 @@ clean_up_internal_tempdir(void)
        struct stat st;
        time_t now = time(NULL);
 
-       stat(conf->cache_dir, &st);
-       if (st.st_mtime + 3600 >= now) {
+       if (x_stat(conf->cache_dir, &st) != 0 || st.st_mtime + 3600 >= now) {
                /* No cleanup needed. */
                return;
        }
@@ -332,7 +349,7 @@ clean_up_internal_tempdir(void)
                }
 
                path = format("%s/%s", temp_dir(), entry->d_name);
-               if (lstat(path, &st) == 0 && st.st_mtime + 3600 < now) {
+               if (x_lstat(path, &st) == 0 && st.st_mtime + 3600 < now) {
                        tmp_unlink(path);
                }
                free(path);
@@ -423,8 +440,7 @@ remember_include_file(char *path, struct mdfour *cpp_hash)
                goto ignore;
 #endif
 
-       if (stat(path, &st) != 0) {
-               cc_log("Failed to stat include file %s: %s", path, strerror(errno));
+       if (x_stat(path, &st) != 0) {
                goto failure;
        }
        if (S_ISDIR(st.st_mode)) {
@@ -689,8 +705,7 @@ put_file_in_cache(const char *source, const char *dest)
                failed();
        }
        cc_log("Stored in cache: %s -> %s", source, dest);
-       if (stat(dest, &st) != 0) {
-               cc_log("Failed to stat %s: %s", dest, strerror(errno));
+       if (x_stat(dest, &st) != 0) {
                stats_update(STATS_ERROR);
                failed();
        }
@@ -724,34 +739,91 @@ get_file_from_cache(const char *source, const char *dest)
                               strerror(errno));
                        stats_update(STATS_ERROR);
                }
+
+               /* If there was trouble getting a file from the cached result, wipe the
+                * whole cached result for consistency. */
+               x_unlink(cached_stderr);
+               x_unlink(cached_obj);
+               x_unlink(cached_dep);
+               x_unlink(cached_dia);
+
                failed();
        }
 
        cc_log("Created from cache: %s -> %s", source, dest);
 }
 
+/* Send cached stderr, if any, to stderr. */
+static void
+send_cached_stderr(void)
+{
+       int fd_stderr = open(cached_stderr, O_RDONLY | O_BINARY);
+       if (fd_stderr != -1) {
+               copy_fd(fd_stderr, 2);
+               close(fd_stderr);
+       }
+}
+
+/* Create or update the manifest file. */
+void update_manifest_file(void)
+{
+       struct stat st;
+       size_t old_size = 0; /* in bytes */
+
+       if (!conf->direct_mode
+           || !included_files
+           || conf->read_only
+           || conf->read_only_direct) {
+               return;
+       }
+
+       if (stat(manifest_path, &st) == 0) {
+               old_size = file_size(&st);
+       }
+       if (manifest_put(manifest_path, cached_obj_hash, included_files)) {
+               cc_log("Added object file hash to %s", manifest_path);
+               update_mtime(manifest_path);
+               if (x_stat(manifest_path, &st) == 0) {
+                       stats_update_size(file_size(&st) - old_size, old_size == 0 ? 1 : 0);
+               }
+       } else {
+               cc_log("Failed to add object file hash to %s", manifest_path);
+       }
+}
+
 /* run the real compiler and put the result in cache */
 static void
 to_cache(struct args *args)
 {
-       char *tmp_stdout, *tmp_stderr, *tmp_dia;
+       char *tmp_stdout, *tmp_stderr, *tmp_aux, *tmp_cov;
        struct stat st;
        int status, tmp_stdout_fd, tmp_stderr_fd;
+       FILE *f;
 
        tmp_stdout = format("%s.tmp.stdout", cached_obj);
        tmp_stdout_fd = create_tmp_fd(&tmp_stdout);
        tmp_stderr = format("%s.tmp.stderr", cached_obj);
        tmp_stderr_fd = create_tmp_fd(&tmp_stderr);
 
+       if (generating_coverage) {
+               /* gcc has some funny rule about max extension length */
+               if (strlen(get_extension(output_obj)) < 6) {
+                       tmp_aux = remove_extension(output_obj);
+               } else {
+                       tmp_aux = x_strdup(output_obj);
+               }
+               tmp_cov = format("%s.gcno", tmp_aux);
+               free(tmp_aux);
+       } else {
+               tmp_cov = NULL;
+       }
+
        args_add(args, "-o");
        args_add(args, output_obj);
 
        if (output_dia) {
-               tmp_dia = x_strdup(output_dia);
                args_add(args, "--serialize-diagnostics");
-               args_add(args, tmp_dia);
-       } else {
-               tmp_dia = NULL;
+               args_add(args, output_dia);
        }
 
        /* Turn off DEPENDENCIES_OUTPUT when running cc1, because
@@ -771,12 +843,14 @@ to_cache(struct args *args)
        status = execute(args->argv, tmp_stdout_fd, tmp_stderr_fd);
        args_pop(args, 3);
 
-       if (stat(tmp_stdout, &st) != 0) {
+       if (x_stat(tmp_stdout, &st) != 0) {
                /* The stdout file was removed - cleanup in progress? Better bail out. */
-               cc_log("%s not found: %s", tmp_stdout, strerror(errno));
                stats_update(STATS_MISSING);
                tmp_unlink(tmp_stdout);
                tmp_unlink(tmp_stderr);
+               if (tmp_cov) {
+                       tmp_unlink(tmp_cov);
+               }
                failed();
        }
        if (st.st_size != 0) {
@@ -784,8 +858,8 @@ to_cache(struct args *args)
                stats_update(STATS_STDOUT);
                tmp_unlink(tmp_stdout);
                tmp_unlink(tmp_stderr);
-               if (tmp_dia) {
-                       tmp_unlink(tmp_dia);
+               if (tmp_cov) {
+                       tmp_unlink(tmp_cov);
                }
                failed();
        }
@@ -838,47 +912,22 @@ to_cache(struct args *args)
 
                fd = open(tmp_stderr, O_RDONLY | O_BINARY);
                if (fd != -1) {
-                       if (str_eq(output_obj, "/dev/null") || errno == ENOENT) {
-                               /* we can use a quick method of getting the failed output */
-                               copy_fd(fd, 2);
-                               close(fd);
-                               tmp_unlink(tmp_stderr);
-
-                               if (output_dia) {
-                                       int ret;
-                                       x_unlink(output_dia);
-                                       /* only make a hardlink if the cache file is uncompressed */
-                                       ret = move_file(tmp_dia, output_dia, 0);
-
-                                       if (ret == -1) {
-                                               if (errno == ENOENT) {
-                                                       /* Someone removed the file just before we began copying? */
-                                                       cc_log("Diagnostic file %s just disappeared", output_dia);
-                                                       stats_update(STATS_MISSING);
-                                               } else {
-                                                       cc_log("Failed to move %s to %s: %s",
-                                                              tmp_dia, output_dia, strerror(errno));
-                                                       stats_update(STATS_ERROR);
-                                                       failed();
-                                               }
-                                               x_unlink(tmp_dia);
-                                       } else {
-                                               cc_log("Created %s from %s", output_dia, tmp_dia);
-                                       }
-                               }
+                       /* We can output stderr immediately instead of rerunning the compiler. */
+                       copy_fd(fd, 2);
+                       close(fd);
+                       tmp_unlink(tmp_stderr);
 
-                               exit(status);
-                       }
+                       exit(status);
                }
 
                tmp_unlink(tmp_stderr);
-               if (tmp_dia) {
-                       tmp_unlink(tmp_dia);
+               if (tmp_cov) {
+                       tmp_unlink(tmp_cov);
                }
                failed();
        }
 
-       if (stat(output_obj, &st) != 0) {
+       if (x_stat(output_obj, &st) != 0) {
                cc_log("Compiler didn't produce an object file");
                stats_update(STATS_NOOUTPUT);
                failed();
@@ -889,8 +938,7 @@ to_cache(struct args *args)
                failed();
        }
 
-       if (stat(tmp_stderr, &st) != 0) {
-               cc_log("Failed to stat %s: %s", tmp_stderr, strerror(errno));
+       if (x_stat(tmp_stderr, &st) != 0) {
                stats_update(STATS_ERROR);
                failed();
        }
@@ -904,10 +952,11 @@ to_cache(struct args *args)
                        failed();
                }
                cc_log("Stored in cache: %s", cached_stderr);
-               if (conf->compression) {
-                       stat(cached_stderr, &st);
+               if (!conf->compression
+                   /* If the file was compressed, obtain the size again: */
+                   || (conf->compression && x_stat(cached_stderr, &st) == 0)) {
+                       stats_update_size(file_size(&st), 1);
                }
-               stats_update_size(file_size(&st), 1);
        } else {
                tmp_unlink(tmp_stderr);
                if (conf->recache) {
@@ -916,18 +965,38 @@ to_cache(struct args *args)
                }
        }
 
-       if (tmp_dia) {
-               if (stat(tmp_dia, &st) != 0) {
-                       cc_log("Failed to stat %s: %s", tmp_dia, strerror(errno));
+       if (generating_coverage) {
+               /* gcc won't generate notes if there is no code */
+               if (stat(tmp_cov, &st) != 0 && errno == ENOENT) {
+                       cc_log("Creating placeholder: %s", cached_cov);
+
+                       f = fopen(cached_cov, "wb");
+                       if (!f) {
+                               cc_log("Failed to create %s: %s", cached_cov, strerror(errno));
+                               stats_update(STATS_ERROR);
+                               failed();
+                       }
+                       fclose(f);
+                       stats_update_size(0, 1);
+               } else {
+                       put_file_in_cache(tmp_cov, cached_cov);
+               }
+       }
+
+       if (output_dia) {
+               if (x_stat(output_dia, &st) != 0) {
                        stats_update(STATS_ERROR);
                        failed();
                }
                if (st.st_size > 0) {
-                       put_file_in_cache(tmp_dia, cached_dia);
+                       put_file_in_cache(output_dia, cached_dia);
                }
        }
 
        put_file_in_cache(output_obj, cached_obj);
+       if (generating_dependencies) {
+               put_file_in_cache(output_dep, cached_dep);
+       }
        stats_update(STATS_TOCACHE);
 
        /* Make sure we have a CACHEDIR.TAG in the cache part of cache_dir. This can
@@ -948,14 +1017,18 @@ to_cache(struct args *args)
                 * previous ccache versions. */
                if (getpid() % 1000 == 0) {
                        char *path = format("%s/CACHEDIR.TAG", conf->cache_dir);
-                       unlink(path);
+                       x_unlink(path);
                        free(path);
                }
        }
 
+       /* Everything OK. */
+       send_cached_stderr();
+       update_manifest_file();
+
        free(tmp_stderr);
        free(tmp_stdout);
-       free(tmp_dia);
+       free(tmp_cov);
 }
 
 /*
@@ -1059,6 +1132,8 @@ get_object_name_from_cpp(struct args *args, struct mdfour *hash)
                 * the compiler pass.
                 */
                cpp_stderr = path_stderr;
+               hash_delimiter(hash, "runsecondcpp");
+               hash_string(hash, "false");
        }
 
        result = x_malloc(sizeof(*result));
@@ -1076,6 +1151,7 @@ update_cached_result_globals(struct file_hash *hash)
        cached_obj = get_path_in_cache(object_name, ".o");
        cached_stderr = get_path_in_cache(object_name, ".stderr");
        cached_dep = get_path_in_cache(object_name, ".d");
+       cached_cov = get_path_in_cache(object_name, ".gcno");
        cached_dia = get_path_in_cache(object_name, ".dia");
        stats_file = format("%s/%c/stats", conf->cache_dir, object_name[0]);
        free(object_name);
@@ -1095,6 +1171,9 @@ hash_compiler(struct mdfour *hash, struct stat *st, const char *path,
                hash_delimiter(hash, "cc_mtime");
                hash_int(hash, st->st_size);
                hash_int(hash, st->st_mtime);
+       } else if (str_startswith(conf->compiler_check, "string:")) {
+               hash_delimiter(hash, "cc_hash");
+               hash_string(hash, conf->compiler_check + strlen("string:"));
        } else if (str_eq(conf->compiler_check, "content") || !allow_command) {
                hash_delimiter(hash, "cc_content");
                hash_file(hash, path);
@@ -1114,7 +1193,7 @@ hash_compiler(struct mdfour *hash, struct stat *st, const char *path,
 static bool
 compiler_is_clang(struct args *args)
 {
-       charname = basename(args->argv[0]);
+       char *name = basename(args->argv[0]);
        bool is = strstr(name, "clang");
        free(name);
        return is;
@@ -1123,7 +1202,7 @@ compiler_is_clang(struct args *args)
 static bool
 compiler_is_gcc(struct args *args)
 {
-       charname = basename(args->argv[0]);
+       char *name = basename(args->argv[0]);
        bool is = strstr(name, "gcc") || strstr(name, "g++");
        free(name);
        return is;
@@ -1138,6 +1217,11 @@ calculate_common_hash(struct args *args, struct mdfour *hash)
 {
        struct stat st;
        char *p;
+       const char *full_path = args->argv[0];
+#ifdef _WIN32
+       const char *ext;
+       char full_path_win_ext[MAX_PATH + 1] = {0};
+#endif
 
        hash_string(hash, HASH_PREFIX);
 
@@ -1148,8 +1232,14 @@ calculate_common_hash(struct args *args, struct mdfour *hash)
        hash_delimiter(hash, "ext");
        hash_string(hash, conf->cpp_extension);
 
-       if (stat(args->argv[0], &st) != 0) {
-               cc_log("Couldn't stat compiler %s: %s", args->argv[0], strerror(errno));
+#ifdef _WIN32
+       ext = strrchr(args->argv[0], '.');
+       add_exe_ext_if_no_to_fullpath(full_path_win_ext, MAX_PATH, ext,
+                                     args->argv[0]);
+       full_path = full_path_win_ext;
+#endif
+
+       if (x_stat(full_path, &st) != 0) {
                stats_update(STATS_COMPILER);
                failed();
        }
@@ -1178,6 +1268,30 @@ calculate_common_hash(struct args *args, struct mdfour *hash)
                }
        }
 
+       /* Possibly hash the coverage data file path. */
+       if (generating_coverage && profile_arcs) {
+               char *gcda_path;
+               char *dir = dirname(output_obj);
+               if (profile_dir) {
+                       dir = x_strdup(profile_dir);
+               } else {
+                       char *real_dir = x_realpath(dir);
+                       free(dir);
+                       dir = real_dir;
+               }
+               if (dir) {
+                       char *base_name = basename(output_obj);
+                       p = remove_extension(base_name);
+                       free(base_name);
+                       gcda_path = format("%s/%s.gcda", dir, p);
+                       cc_log("Hashing coverage path %s", gcda_path);
+                       free(p);
+                       hash_delimiter(hash, "gcda");
+                       hash_string(hash, gcda_path);
+                       free(dir);
+               }
+       }
+
        if (!str_eq(conf->extra_files_to_hash, "")) {
                char *path, *p, *q, *saveptr = NULL;
                p = x_strdup(conf->extra_files_to_hash);
@@ -1269,11 +1383,11 @@ calculate_object_hash(struct args *args, struct mdfour *hash, int direct_mode)
                if (generating_dependencies) {
                        if (str_startswith(args->argv[i], "-Wp,")) {
                                if (str_startswith(args->argv[i], "-Wp,-MD,")
-                                               && !strchr(args->argv[i] + 8, ',')) {
+                                   && !strchr(args->argv[i] + 8, ',')) {
                                        hash_string_length(hash, args->argv[i], 8);
                                        continue;
                                } else if (str_startswith(args->argv[i], "-Wp,-MMD,")
-                                               && !strchr(args->argv[i] + 9, ',')) {
+                                          && !strchr(args->argv[i] + 9, ',')) {
                                        hash_string_length(hash, args->argv[i], 9);
                                        continue;
                                }
@@ -1298,7 +1412,7 @@ calculate_object_hash(struct args *args, struct mdfour *hash, int direct_mode)
                } else if (str_startswith(args->argv[i], "--specs=")) {
                        p = args->argv[i] + 8;
                }
-               if (p && stat(p, &st) == 0) {
+               if (p && x_stat(p, &st) == 0) {
                        /* If given an explicit specs file, then hash that file,
                           but don't include the path to it in the hash. */
                        hash_delimiter(hash, "specs");
@@ -1307,7 +1421,7 @@ calculate_object_hash(struct args *args, struct mdfour *hash, int direct_mode)
                }
 
                if (str_startswith(args->argv[i], "-fplugin=")
-                   && stat(args->argv[i] + 9, &st) == 0) {
+                   && x_stat(args->argv[i] + 9, &st) == 0) {
                        hash_delimiter(hash, "plugin");
                        hash_compiler(hash, &st, args->argv[i] + 9, false);
                        continue;
@@ -1317,7 +1431,7 @@ calculate_object_hash(struct args *args, struct mdfour *hash, int direct_mode)
                    && i + 3 < args->argc
                    && str_eq(args->argv[i+1], "-load")
                    && str_eq(args->argv[i+2], "-Xclang")
-                   && stat(args->argv[i+3], &st) == 0) {
+                   && x_stat(args->argv[i+3], &st) == 0) {
                        hash_delimiter(hash, "plugin");
                        hash_compiler(hash, &st, args->argv[i+3], false);
                        continue;
@@ -1439,12 +1553,11 @@ calculate_object_hash(struct args *args, struct mdfour *hash, int direct_mode)
 static void
 from_cache(enum fromcache_call_mode mode, bool put_object_in_manifest)
 {
-       int fd_stderr;
        struct stat st;
-       bool produce_dep_file;
+       bool produce_dep_file = false;
 
        /* the user might be disabling cache hits */
-       if (mode != FROMCACHE_COMPILED_MODE && conf->recache) {
+       if (conf->recache) {
                return;
        }
 
@@ -1462,7 +1575,7 @@ from_cache(enum fromcache_call_mode mode, bool put_object_in_manifest)
 
        /*
         * Occasionally, e.g. on hard reset, our cache ends up as just filesystem
-        * meta-data with no content catch an easy case of this.
+        * meta-data with no content. Catch an easy case of this.
         */
        if (st.st_size == 0) {
                cc_log("Invalid (empty) object file %s in cache", cached_obj);
@@ -1488,6 +1601,10 @@ from_cache(enum fromcache_call_mode mode, bool put_object_in_manifest)
        if (produce_dep_file) {
                get_file_from_cache(cached_dep, output_dep);
        }
+       if (generating_coverage && stat(cached_cov, &st) == 0 && st.st_size > 0) {
+               /* gcc won't generate notes if there is no code */
+               get_file_from_cache(cached_cov, output_cov);
+       }
        if (output_dia) {
                get_file_from_cache(cached_dia, output_dia);
        }
@@ -1499,40 +1616,21 @@ from_cache(enum fromcache_call_mode mode, bool put_object_in_manifest)
        if (produce_dep_file) {
                update_mtime(cached_dep);
        }
+       if (generating_coverage) {
+               update_mtime(cached_cov);
+       }
        if (output_dia) {
                update_mtime(cached_dia);
        }
 
-       if (generating_dependencies && mode != FROMCACHE_DIRECT_MODE) {
+       if (generating_dependencies && mode == FROMCACHE_CPP_MODE) {
                put_file_in_cache(output_dep, cached_dep);
        }
 
-       /* Send the stderr, if any. */
-       fd_stderr = open(cached_stderr, O_RDONLY | O_BINARY);
-       if (fd_stderr != -1) {
-               copy_fd(fd_stderr, 2);
-               close(fd_stderr);
-       }
+  send_cached_stderr();
 
-       /* Create or update the manifest file. */
-       if (conf->direct_mode
-           && put_object_in_manifest
-           && included_files
-           && !conf->read_only
-           && !conf->read_only_direct) {
-               struct stat st;
-               size_t old_size = 0; /* in bytes */
-               if (stat(manifest_path, &st) == 0) {
-                       old_size = file_size(&st);
-               }
-               if (manifest_put(manifest_path, cached_obj_hash, included_files)) {
-                       cc_log("Added object file hash to %s", manifest_path);
-                       update_mtime(manifest_path);
-                       stat(manifest_path, &st);
-                       stats_update_size(file_size(&st) - old_size, old_size == 0 ? 1 : 0);
-               } else {
-                       cc_log("Failed to add object file hash to %s", manifest_path);
-               }
+       if (put_object_in_manifest) {
+               update_manifest_file();
        }
 
        /* log the cache hit */
@@ -1546,10 +1644,6 @@ from_cache(enum fromcache_call_mode mode, bool put_object_in_manifest)
                cc_log("Succeeded getting cached result");
                stats_update(STATS_CACHEHIT_CPP);
                break;
-
-       case FROMCACHE_COMPILED_MODE:
-               /* Stats already updated in to_cache(). */
-               break;
        }
 
        /* and exit with the right status code */
@@ -1873,6 +1967,27 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
                        }
                        continue;
                }
+               if (str_eq(argv[i], "-fprofile-arcs")) {
+                       profile_arcs = true;
+                       args_add(stripped_args, argv[i]);
+                       continue;
+               }
+               if (str_eq(argv[i], "-ftest-coverage")) {
+                       generating_coverage = true;
+                       args_add(stripped_args, argv[i]);
+                       continue;
+               }
+               if (str_eq(argv[i], "--coverage")) { /* = -fprofile-arcs -ftest-coverage */
+                       profile_arcs = true;
+                       generating_coverage = true;
+                       args_add(stripped_args, argv[i]);
+                       continue;
+               }
+               if (str_startswith(argv[i], "-fprofile-dir=")) {
+                       profile_dir = x_strdup(argv[i] + 14);
+                       args_add(stripped_args, argv[i]);
+                       continue;
+               }
                if (str_startswith(argv[i], "--sysroot=")) {
                        char *relpath = make_relative_path(x_strdup(argv[i] + 10));
                        char *option = format("--sysroot=%s", relpath);
@@ -2172,6 +2287,12 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
                        goto out;
                }
 
+               /* The source code file path gets put into the notes */
+               if (generating_coverage) {
+                       input_file = x_strdup(argv[i]);
+                       continue;
+               }
+
                /* Rewrite to relative to increase hit rate. */
                input_file = make_relative_path(x_strdup(argv[i]));
        }
@@ -2358,6 +2479,15 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
                        args_add(dep_args, output_obj);
                }
        }
+       if (generating_coverage) {
+               char *default_covfile_name;
+               char *base_name;
+
+               base_name = remove_extension(output_obj);
+               default_covfile_name = format("%s.gcno", base_name);
+               free(base_name);
+               output_cov = make_relative_path(x_strdup(default_covfile_name));
+       }
 
        *compiler_args = args_copy(stripped_args);
        if (conf->run_second_cpp) {
@@ -2525,11 +2655,13 @@ cc_reset(void)
        free(input_file); input_file = NULL;
        free(output_obj); output_obj = NULL;
        free(output_dep); output_dep = NULL;
+       free(output_cov); output_cov = NULL;
        free(output_dia); output_dia = NULL;
        free(cached_obj_hash); cached_obj_hash = NULL;
        free(cached_obj); cached_obj = NULL;
        free(cached_stderr); cached_stderr = NULL;
        free(cached_dep); cached_dep = NULL;
+       free(cached_cov); cached_cov = NULL;
        free(cached_dia); cached_dia = NULL;
        free(manifest_path); manifest_path = NULL;
        time_of_compilation = 0;
@@ -2537,6 +2669,9 @@ cc_reset(void)
                hashtable_destroy(included_files, 1); included_files = NULL;
        }
        generating_dependencies = false;
+       generating_coverage = false;
+       profile_arcs = false;
+       free(profile_dir); profile_dir = NULL;
        i_tmpfile = NULL;
        direct_i_file = false;
        free(cpp_stderr); cpp_stderr = NULL;
@@ -2636,6 +2771,9 @@ ccache(int argc, char *argv[])
        if (generating_dependencies) {
                cc_log("Dependency file: %s", output_dep);
        }
+       if (generating_coverage) {
+               cc_log("Coverage file: %s", output_cov);
+       }
        if (output_dia) {
                cc_log("Diagnostic file: %s", output_dia);
        }
@@ -2726,13 +2864,7 @@ ccache(int argc, char *argv[])
        /* run real compiler, sending output to cache */
        to_cache(compiler_args);
 
-       /* return from cache */
-       from_cache(FROMCACHE_COMPILED_MODE, put_object_in_manifest);
-
-       /* oh oh! */
-       cc_log("Secondary from_cache failed");
-       stats_update(STATS_ERROR);
-       failed();
+       exit(0);
 }
 
 static void
index 6fdd55f6c88e7f1e33275e92a40aa971d2a5109d..6028f46c66704126d1eea4ebe44ada9bb3037292 100644 (file)
--- a/ccache.h
+++ b/ccache.h
@@ -136,6 +136,9 @@ void *x_malloc(size_t size);
 void *x_calloc(size_t nmemb, size_t size);
 void *x_realloc(void *ptr, size_t size);
 void x_unsetenv(const char *name);
+int x_fstat(int fd, struct stat *buf);
+int x_lstat(const char *pathname, struct stat *buf);
+int x_stat(const char *pathname, struct stat *buf);
 void traverse(const char *dir, void (*fn)(const char *, struct stat *));
 char *basename(const char *path);
 char *dirname(const char *path);
@@ -251,7 +254,9 @@ typedef int (*COMPAR_FN_T)(const void *, const void *);
 char *win32argvtos(char *prefix, char **argv);
 char *win32getshell(char *path);
 int win32execute(char *path, char **argv, int doreturn,
-                 const char *path_stdout, const char *path_stderr);
+                 int fd_stdout, int fd_stderr);
+void add_exe_ext_if_no_to_fullpath(char *full_path_win_ext, size_t max_size,
+                                   const char *ext, const char *path);
 #    ifndef _WIN32_WINNT
 #    define _WIN32_WINNT 0x0501
 #    endif
@@ -259,8 +264,7 @@ int win32execute(char *path, char **argv, int doreturn,
 #    define mkdir(a,b) mkdir(a)
 #    define link(src,dst) (CreateHardLink(dst,src,NULL) ? 0 : -1)
 #    define lstat(a,b) stat(a,b)
-#    define execv(a,b) win32execute(a,b,0,NULL,NULL)
-#error TODO: Adapt win32execute to new execute API
+#    define execv(a,b) win32execute(a,b,0,-1,-1)
 #    define execute(a,b,c) win32execute(*(a),a,1,b,c)
 #    define PATH_DELIM ";"
 #    define F_RDLCK 0
index ee872ccbf12295abed9b291b76dfc9d27e6e3b49..981423d9ab413d9480fabdd82bcc989672490939 100644 (file)
--- a/cleanup.c
+++ b/cleanup.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2002-2006 Andrew Tridgell
- * Copyright (C) 2009-2014 Joel Rosdahl
+ * Copyright (C) 2009-2015 Joel Rosdahl
  *
  * 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
@@ -122,7 +122,7 @@ delete_sibling_file(const char *base, const char *extension)
        if (lstat(path, &st) == 0) {
                delete_file(path, file_size(&st));
        } else if (errno != ENOENT) {
-               cc_log("Failed to stat %s (%s)", path, strerror(errno));
+               cc_log("Failed to stat %s: %s", path, strerror(errno));
        }
        free(path);
 }
@@ -153,6 +153,7 @@ sort_and_clean(void)
                ext = get_extension(files[i]->fname);
                if (str_eq(ext, ".o")
                    || str_eq(ext, ".d")
+                   || str_eq(ext, ".gcno")
                    || str_eq(ext, ".dia")
                    || str_eq(ext, ".stderr")
                    || str_eq(ext, "")) {
@@ -167,6 +168,7 @@ sort_and_clean(void)
                                 */
                                delete_sibling_file(base, ".o");
                                delete_sibling_file(base, ".d");
+                               delete_sibling_file(base, ".gcno");
                                delete_sibling_file(base, ".dia");
                                delete_sibling_file(base, ".stderr");
                                delete_sibling_file(base, ""); /* Object file from ccache 2.4. */
index 1996fdfc36d25c912b6e62723bd014f6d6b784a8..41f710daab727480c38c068d5f82323fc82a9cf2 100644 (file)
--- a/compopt.c
+++ b/compopt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, 2012-2013 Joel Rosdahl
+ * Copyright (C) 2010-2015 Joel Rosdahl
  *
  * 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
@@ -32,7 +32,6 @@ struct compopt {
 };
 
 static const struct compopt compopts[] = {
-       {"--coverage",      TOO_HARD}, /* implies -ftest-coverage */
        {"--param",         TAKES_ARG},
        {"--serialize-diagnostics", TAKES_ARG | TAKES_PATH},
        {"-A",              TAKES_ARG},
@@ -56,9 +55,10 @@ static const struct compopt compopts[] = {
        {"-arch",           TAKES_ARG},
        {"-aux-info",       TAKES_ARG},
        {"-b",              TAKES_ARG},
+       {"-fmodules",       TOO_HARD},
        {"-fno-working-directory", AFFECTS_CPP},
+       {"-fplugin=libcc1plugin", TOO_HARD}, /* interaction with GDB */
        {"-frepo",          TOO_HARD},
-       {"-ftest-coverage", TOO_HARD}, /* generates a .gcno file at the same time */
        {"-fworking-directory", AFFECTS_CPP},
        {"-gsplit-dwarf",   TOO_HARD}, /* generates a .dwo file at the same time */
        {"-idirafter",      AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
index 29cd51c355669861f2606b330c81b09e5a584d96..b004bd409cd289a3b5cf5f0677bc7f210f773ad0 100755 (executable)
--- a/configure
+++ b/configure
@@ -2327,6 +2327,7 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
 
 case $host in
     *mingw32* | *cygwin* | *wince* | *mingwce*)
+        windows_os=yes
 
 $as_echo "#define _WIN32_WINNT 0x0600" >>confdefs.h
 
@@ -5684,6 +5685,10 @@ else
     extra_ldflags="-lz"
 fi
 
+if test x${windows_os} = xyes; then
+    extra_ldflags="$extra_ldflags -lws2_32"
+fi
+
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
 $as_echo_n "checking whether byte ordering is bigendian... " >&6; }
 if ${ac_cv_c_bigendian+:} false; then :
index 2cf2939266f0a2c644d87e32282b3cc4e09f057f..9e655889488cdc0f2b9f63197e922e649c6930a2 100644 (file)
@@ -11,6 +11,7 @@ AC_CANONICAL_HOST
 
 case $host in
     *mingw32* | *cygwin* | *wince* | *mingwce*)
+        windows_os=yes
         AC_DEFINE(_WIN32_WINNT,0x0600, Windows Vista or newer is required)
         ;;
 esac
@@ -122,6 +123,11 @@ else
     extra_ldflags="-lz"
 fi
 
+dnl Linking on Windows needs ws2_32
+if test x${windows_os} = xyes; then
+    extra_ldflags="$extra_ldflags -lws2_32"
+fi
+
 AC_C_BIGENDIAN
 
 AC_C_INLINE
index 2642dd66fa2620a8e36e8359ff38df8e2ce9bb2b..39e95afaf46f9b931d8b52b50865ec5c6f4d6a61 100644 (file)
@@ -75,6 +75,7 @@ confitems_hash (register const char *str, register unsigned int len)
   return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
 }
 
+static
 #ifdef __GNUC__
 __inline
 #if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
index 914e7e5f902f6e6640ae5be4dedc4818ba5fc4ac..adc3557f01f9b77b42b81ffe9649204e32d59908 100644 (file)
--- a/dev.mk.in
+++ b/dev.mk.in
@@ -92,7 +92,7 @@ endif
 version.o: version.c
 
 %_lookup.c: %.gperf
-       $(GPERF) $< >$@
+       $(GPERF) $< | awk '/#ifdef __GNUC__/ { ++i; if (i == 2) { print "static"; }} {print}' >$@
        echo "static const size_t `echo $* | tr a-z A-Z`_TOTAL_KEYWORDS = `sed -nr 's/.*TOTAL_KEYWORDS = ([0-9]+).*/\1/p' $@`;" >>$@
 
 .PHONY: dist
index 2bfd2f820646e870c64e0786d28f540da836f9c5..cb8b53e5218da21deb22e280df5f9207dc9abecd 100644 (file)
@@ -89,6 +89,7 @@ envtoconfitems_hash (register const char *str, register unsigned int len)
   return hval;
 }
 
+static
 #ifdef __GNUC__
 __inline
 #if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
index 78f1e4b7888e9a948c58ee92042e4e10c252ecf8..94d605dc6ad43a8df0855fdde122c8a1908aec28 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -117,9 +117,21 @@ win32getshell(char *path)
        return sh;
 }
 
+void add_exe_ext_if_no_to_fullpath(char *full_path_win_ext, size_t max_size,
+                                   const char *ext, const char *path) {
+       if (!ext || (!str_eq(".exe", ext)
+                    && !str_eq(".bat", ext)
+                    && !str_eq(".EXE", ext)
+                    && !str_eq(".BAT", ext))) {
+               snprintf(full_path_win_ext, max_size, "%s.exe", path);
+       } else {
+               snprintf(full_path_win_ext, max_size, "%s", path);
+       }
+}
+
 int
 win32execute(char *path, char **argv, int doreturn,
-             const char *path_stdout, const char *path_stderr)
+             int fd_stdout, int fd_stderr)
 {
        PROCESS_INFORMATION pi;
        STARTUPINFO si;
@@ -136,29 +148,67 @@ win32execute(char *path, char **argv, int doreturn,
                path = sh;
 
        si.cb = sizeof(STARTUPINFO);
-       if (path_stdout) {
-               SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
-               si.hStdOutput = CreateFile(path_stdout, GENERIC_WRITE, 0, &sa,
-                                          CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY |
-                                          FILE_FLAG_SEQUENTIAL_SCAN, NULL);
-               si.hStdError  = CreateFile(path_stderr, GENERIC_WRITE, 0, &sa,
-                                          CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY |
-                                          FILE_FLAG_SEQUENTIAL_SCAN, NULL);
-               si.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
-               si.dwFlags    = STARTF_USESTDHANDLES;
-               if (si.hStdOutput == INVALID_HANDLE_VALUE ||
-                   si.hStdError  == INVALID_HANDLE_VALUE)
+       if (fd_stdout != -1) {
+               si.hStdOutput = (HANDLE)_get_osfhandle(fd_stdout);
+               si.hStdError = (HANDLE)_get_osfhandle(fd_stderr);
+               si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+               si.dwFlags = STARTF_USESTDHANDLES;
+               if (si.hStdOutput == INVALID_HANDLE_VALUE
+                   || si.hStdError == INVALID_HANDLE_VALUE) {
                        return -1;
+               }
+       } else {
+               /* redirect subprocess stdout, stderr into current process */
+               si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+               si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+               si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+               si.dwFlags = STARTF_USESTDHANDLES;
+               if (si.hStdOutput == INVALID_HANDLE_VALUE
+                   || si.hStdError == INVALID_HANDLE_VALUE) {
+                       return -1;
+               }
        }
        args = win32argvtos(sh, argv);
-       ret = CreateProcess(path, args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
-       free(args);
-       if (path_stdout) {
-               CloseHandle(si.hStdOutput);
-               CloseHandle(si.hStdError);
+
+       const char *ext = strrchr(path, '.');
+       char full_path_win_ext[MAX_PATH] = {0};
+       add_exe_ext_if_no_to_fullpath(full_path_win_ext, MAX_PATH, ext, path);
+       ret = CreateProcess(full_path_win_ext, args, NULL, NULL, 1, 0, NULL, NULL,
+                           &si, &pi);
+       if (fd_stdout != -1) {
+               close(fd_stdout);
+               close(fd_stderr);
        }
-       if (ret == 0)
+       free(args);
+       if (ret == 0) {
+               LPVOID lpMsgBuf;
+               LPVOID lpDisplayBuf;
+               DWORD dw = GetLastError();
+
+               FormatMessage(
+                       FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                       FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS,
+                       NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,
+                       0, NULL);
+
+               lpDisplayBuf =
+                       (LPVOID) LocalAlloc(LMEM_ZEROINIT,
+                                           (lstrlen((LPCTSTR) lpMsgBuf)
+                                            + lstrlen((LPCTSTR) __FILE__) + 200)
+                                           * sizeof(TCHAR));
+               _snprintf((LPTSTR) lpDisplayBuf,
+                         LocalSize(lpDisplayBuf) / sizeof(TCHAR),
+                         TEXT("%s failed with error %d: %s"), __FILE__, dw, lpMsgBuf);
+
+               cc_log("can't execute %s; OS returned error: %s",
+                      full_path_win_ext, (char*)lpDisplayBuf);
+
+               LocalFree(lpMsgBuf);
+               LocalFree(lpDisplayBuf);
+
                return -1;
+       }
        WaitForSingleObject(pi.hProcess, INFINITE);
        GetExitCodeProcess(pi.hProcess, &exitcode);
        CloseHandle(pi.hProcess);
diff --git a/hash.c b/hash.c
index 80beed23aebf6bcdd9f94b0a7dd5ee9103302f89..7950737890f99744d4352353256932c6b72ecd5a 100644 (file)
--- a/hash.c
+++ b/hash.c
@@ -128,6 +128,7 @@ hash_file(struct mdfour *md, const char *fname)
 
        fd = open(fname, O_RDONLY|O_BINARY);
        if (fd == -1) {
+               cc_log("Failed to open %s: %s", fname, strerror(errno));
                return false;
        }
 
index 82b73675c88aa3761adf7b9c36ba03fd7278c5db..b8103a630bfe458347470c1e770fc6b36efa70fd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2012 Joel Rosdahl
+ * Copyright (C) 2009-2015 Joel Rosdahl
  *
  * 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
@@ -18,8 +18,8 @@
 
 #include "ccache.h"
 #include "hashutil.h"
-#include "murmurhashneutral2.h"
 #include "macroskip.h"
+#include "murmurhashneutral2.h"
 
 unsigned
 hash_from_string(void *str)
@@ -84,7 +84,7 @@ check_for_temporal_macros(const char *str, size_t len)
                                result |= HASH_SOURCE_CODE_FOUND_DATE;
                        }
                        else if (str[i - 5] == 'T' && str[i - 4] == 'I' &&
-                                str[i - 3] == 'M') {
+                                str[i - 3] == 'M') {
                                result |= HASH_SOURCE_CODE_FOUND_TIME;
                        }
                }
index af4fa43af406098bd30644ff40db3846164fa1ca..f4f2028b7d612ae442d69c40d7484900ecd79a92 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2014 Joel Rosdahl
+ * Copyright (C) 2010-2015 Joel Rosdahl
  *
  * 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
@@ -31,6 +31,7 @@
 bool
 lockfile_acquire(const char *path, unsigned staleness_limit)
 {
+       int saved_errno = 0;
        char *lockfile = format("%s.lock", path);
        char *my_content = NULL, *content = NULL, *initial_content = NULL;
        const char *hostname = get_hostname();
@@ -50,15 +51,16 @@ lockfile_acquire(const char *path, unsigned staleness_limit)
 #ifdef _WIN32
                fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0666);
                if (fd == -1) {
+                       saved_errno = errno;
                        cc_log("lockfile_acquire: open WRONLY %s: %s", lockfile, strerror(errno));
-                       if (errno == ENOENT) {
+                       if (saved_errno == ENOENT) {
                                /* Directory doesn't exist? */
                                if (create_parent_dirs(lockfile) == 0) {
                                        /* OK. Retry. */
                                        continue;
                                }
                        }
-                       if (errno != EEXIST) {
+                       if (saved_errno != EEXIST) {
                                /* Directory doesn't exist or isn't writable? */
                                goto out;
                        }
@@ -105,15 +107,16 @@ lockfile_acquire(const char *path, unsigned staleness_limit)
                        acquired = true;
                        goto out;
                }
-               cc_log("lockfile_acquire: symlink %s: %s", lockfile, strerror(errno));
-               if (errno == ENOENT) {
+               saved_errno = errno;
+               cc_log("lockfile_acquire: symlink %s: %s", lockfile, strerror(saved_errno));
+               if (saved_errno == ENOENT) {
                        /* Directory doesn't exist? */
                        if (create_parent_dirs(lockfile) == 0) {
                                /* OK. Retry. */
                                continue;
                        }
                }
-               if (errno == EPERM) {
+               if (saved_errno == EPERM) {
                        /*
                         * The file system does not support symbolic links. We have no choice but
                         * to grant the lock anyway.
@@ -121,7 +124,7 @@ lockfile_acquire(const char *path, unsigned staleness_limit)
                        acquired = true;
                        goto out;
                }
-               if (errno != EEXIST) {
+               if (saved_errno != EEXIST) {
                        /* Directory doesn't exist or isn't writable? */
                        goto out;
                }
index 6eb53fd92996ef9f9cff65bf07d9f044be97e47d..1dcf83f68f40ec60a6b053fd5c5f82c3d7eeeec8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2014 Joel Rosdahl
+ * Copyright (C) 2009-2015 Joel Rosdahl
  *
  * 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
@@ -393,8 +393,7 @@ verify_object(struct conf *conf, struct manifest *mf, struct object *obj,
                st = hashtable_search(hashed_files, path);
                if (!st) {
                        struct stat file_stat;
-                       if (stat(path, &file_stat) == -1) {
-                               cc_log("Failed to stat include file %s: %s", path, strerror(errno));
+                       if (x_stat(path, &file_stat) != 0) {
                                return 0;
                        }
                        st = x_malloc(sizeof(*st));
diff --git a/stats.c b/stats.c
index aef628f9f1a6db6001c71b216c465777e0f17691..72985b46e90e9b5f4fc017d6ab5fc0c813d54191 100644 (file)
--- a/stats.c
+++ b/stats.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2002-2004 Andrew Tridgell
- * Copyright (C) 2009-2014 Joel Rosdahl
+ * Copyright (C) 2009-2015 Joel Rosdahl
  *
  * 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
@@ -153,7 +153,7 @@ init_counter_updates(void)
 
 /*
  * Record that a number of bytes and files have been added to the cache. Size
- * is in KiB.
+ * is in bytes.
  */
 void
 stats_update_size(uint64_t size, unsigned files)
diff --git a/test.sh b/test.sh
index b511146c797fd359580d78d6b1933582a9d0abf8..f14e287dda33a0589b3c478125782a467f9abdc9 100755 (executable)
--- a/test.sh
+++ b/test.sh
@@ -3,7 +3,7 @@
 # A simple test suite for ccache.
 #
 # Copyright (C) 2002-2007 Andrew Tridgell
-# Copyright (C) 2009-2014 Joel Rosdahl
+# Copyright (C) 2009-2015 Joel Rosdahl
 #
 # 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
@@ -240,7 +240,7 @@ base_tests() {
     unset CCACHE_CONFIGPATH
     CCACHE_DISABLE=1 $CCACHE_COMPILE -c test1.c 2> /dev/null
     if [ -d $CCACHE_DIR ]; then
-        test_failed "$CCACHE_DIR created dispite CCACHE_DISABLE being set"
+        test_failed "$CCACHE_DIR created despite CCACHE_DISABLE being set"
     fi
     CCACHE_CONFIGPATH=$saved_config_path
     mv $CCACHE_DIR.saved $CCACHE_DIR
@@ -271,10 +271,10 @@ base_tests() {
     checkstat 'cache miss' 4
     compare_file reference_test1.o test1.o
 
-    # strictly speaking should be 3 - RECACHE causes a double counting!
+    # strictly speaking should be 4 - RECACHE causes a double counting!
     checkstat 'files in cache' 4
     $CCACHE -c > /dev/null
-    checkstat 'files in cache' 3
+    checkstat 'files in cache' 4
 
     testname="CCACHE_HASHDIR"
     CCACHE_HASHDIR=1 $CCACHE_COMPILE -c test1.c -O -O
@@ -285,7 +285,7 @@ base_tests() {
     CCACHE_HASHDIR=1 $CCACHE_COMPILE -c test1.c -O -O
     checkstat 'cache hit (preprocessed)' 6
     checkstat 'cache miss' 5
-    checkstat 'files in cache' 4
+    checkstat 'files in cache' 5
     compare_file reference_test1.o test1.o
 
     testname="comments"
@@ -316,7 +316,7 @@ base_tests() {
     done
     checkstat 'cache hit (preprocessed)' 8
     checkstat 'cache miss' 37
-    checkstat 'files in cache' 36
+    checkstat 'files in cache' 37
 
     $CCACHE -C >/dev/null
 
@@ -374,9 +374,15 @@ base_tests() {
             CCACHE_CPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
             checkstat 'cache hit (preprocessed)' 14
             checkstat 'cache miss' 40
-            $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
+            CCACHE_CPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
             checkstat 'cache hit (preprocessed)' 15
             checkstat 'cache miss' 40
+            $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
+            checkstat 'cache hit (preprocessed)' 15
+            checkstat 'cache miss' 41
+            $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
+            checkstat 'cache hit (preprocessed)' 16
+            checkstat 'cache miss' 41
         fi
     fi
 
@@ -449,6 +455,22 @@ EOF
     checkstat 'cache hit (preprocessed)' 2
     checkstat 'cache miss' 1
 
+    testname="compilercheck=string"
+    $CCACHE -z >/dev/null
+    backdate compiler.sh
+    CCACHE_COMPILERCHECK=string:foo $CCACHE ./compiler.sh -c test1.c
+    checkstat 'cache hit (preprocessed)' 0
+    checkstat 'cache miss' 1
+    CCACHE_COMPILERCHECK=string:foo $CCACHE ./compiler.sh -c test1.c
+    checkstat 'cache hit (preprocessed)' 1
+    checkstat 'cache miss' 1
+    CCACHE_COMPILERCHECK=string:bar $CCACHE ./compiler.sh -c test1.c
+    checkstat 'cache hit (preprocessed)' 1
+    checkstat 'cache miss' 2
+    CCACHE_COMPILERCHECK=string:bar $CCACHE ./compiler.sh -c test1.c
+    checkstat 'cache hit (preprocessed)' 2
+    checkstat 'cache miss' 2
+
     testname="compilercheck=command"
     $CCACHE -z >/dev/null
     backdate compiler.sh
@@ -626,16 +648,45 @@ EOF
     ##################################################################
 
     if [ $COMPILER_TYPE_CLANG -eq 1 ]; then
-        $CCACHE -Cz > /dev/null
         testname="serialize-diagnostics"
-        $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c 2> /dev/null
+        $CCACHE -Cz > /dev/null
+        $COMPILER -c --serialize-diagnostics expected.dia test1.c 2> /dev/null
+        # Run with CCACHE_CPP2 to ensure the same diagnostics output as above
+        CCACHE_CPP2=1 $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c 2> /dev/null
         checkstat 'cache hit (preprocessed)' 0
         checkstat 'cache miss' 1
         checkstat 'files in cache' 2
-        $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c 2> /dev/null
+        compare_file expected.dia test.dia
+        rm -f test.dia
+        CCACHE_CPP2=1 $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c 2> /dev/null
         checkstat 'cache hit (preprocessed)' 1
         checkstat 'cache miss' 1
         checkstat 'files in cache' 2
+        compare_file expected.dia test.dia
+
+        rm -f test.dia
+        rm -f expected.dia
+
+        testname="serialize-diagnostics-compile-failed"
+        $CCACHE -Cz > /dev/null
+        echo "bad source" >error.c
+        $COMPILER -c --serialize-diagnostics expected.dia error.c 2> /dev/null
+        if [ $? -eq 0 ]; then
+            test_failed "expected an error compiling error.c"
+        fi
+        CCACHE_CPP2=1 $CCACHE_COMPILE -c --serialize-diagnostics test.dia error.c 2> /dev/null
+        checkstat 'compile failed' 1
+        checkstat 'cache hit (preprocessed)' 0
+        checkstat 'cache miss' 0
+        checkstat 'files in cache' 0
+        compare_file expected.dia test.dia
+        rm -f test.dia
+        CCACHE_CPP2=1 $CCACHE_COMPILE -c --serialize-diagnostics test.dia error.c 2> /dev/null
+        checkstat 'compile failed' 2
+        checkstat 'cache hit (preprocessed)' 0
+        checkstat 'cache miss' 0
+        checkstat 'files in cache' 0
+        compare_file expected.dia test.dia
     fi
 
     ##################################################################
@@ -710,6 +761,10 @@ int test2;
 EOF
     cat <<EOF >test3.h
 int test3;
+EOF
+    cat <<EOF >code.c
+/* code.c */
+int test() {}
 EOF
     backdate test1.h test2.h test3.h
 
@@ -926,6 +981,35 @@ EOF
     checkfile test.d "$expected_d_content"
     compare_file reference_test.o test.o
 
+    ##################################################################
+    # Check that coverage works.
+    testname="coverage (empty)"
+    $CCACHE -z >/dev/null
+    $CCACHE $COMPILER -c -fprofile-arcs -ftest-coverage test.c
+    checkstat 'cache hit (direct)' 0
+    checkstat 'cache hit (preprocessed)' 0
+    checkstat 'cache miss' 1
+    $CCACHE $COMPILER -c -fprofile-arcs -ftest-coverage test.c
+    checkstat 'cache hit (direct)' 1
+    checkstat 'cache hit (preprocessed)' 0
+    checkstat 'cache miss' 1
+
+    testname="coverage (code)"
+    $CCACHE -z >/dev/null
+    $CCACHE $COMPILER -c -fprofile-arcs -ftest-coverage code.c
+    checkstat 'cache hit (direct)' 0
+    checkstat 'cache hit (preprocessed)' 0
+    checkstat 'cache miss' 1
+    test -r code.gcno || test_failed "gcov"
+
+    rm -f code.gcno
+
+    $CCACHE $COMPILER -c -fprofile-arcs -ftest-coverage code.c
+    checkstat 'cache hit (direct)' 1
+    checkstat 'cache hit (preprocessed)' 0
+    checkstat 'cache miss' 1
+    test -r code.gcno || test_failed "gcov"
+
     ##################################################################
     # Check the scenario of running a ccache with direct mode on a cache
     # built up by a ccache without direct mode support.
@@ -1340,6 +1424,23 @@ EOF
     checkstat 'cache hit (preprocessed)' 0
     checkstat 'cache miss' 2
 
+    testname="comment in strings"
+    $CCACHE -Cz >/dev/null
+    echo 'char *comment = " /* \\\\u" "foo" " */";' >comment.c
+    $CCACHE $COMPILER -c comment.c
+    checkstat 'cache hit (direct)' 0
+    checkstat 'cache hit (preprocessed)' 0
+    checkstat 'cache miss' 1
+    $CCACHE $COMPILER -c comment.c
+    checkstat 'cache hit (direct)' 1
+    checkstat 'cache hit (preprocessed)' 0
+    checkstat 'cache miss' 1
+    echo 'char *comment = " /* \\\\u" "goo" " */";' >comment.c
+    $CCACHE $COMPILER -c comment.c
+    checkstat 'cache hit (direct)' 1
+    checkstat 'cache hit (preprocessed)' 0
+    checkstat 'cache miss' 2
+
     #################################################################
     # Check that strange "#line" directives are handled.
     testname="#line directives with troublesome files"
@@ -2410,7 +2511,6 @@ all_suites="
 base
 link          !win32
 hardlink
-cpp2
 nlevels4
 nlevels1
 basedir       !win32
index 9af5e4e1677e9f315ddb80145736bfdc29aa8a6d..6c17c3d337c03e466b158fd6f81796a33f06f4e0 100644 (file)
@@ -64,6 +64,16 @@ TEST(dash_MD_not_too_hard)
        CHECK(!compopt_too_hard("-MD"));
 }
 
+TEST(dash_fprofile_arcs_not_too_hard)
+{
+       CHECK(!compopt_too_hard("-fprofile-arcs"));
+}
+
+TEST(dash_ftest_coverage_not_too_hard)
+{
+       CHECK(!compopt_too_hard("-ftest-coverage"));
+}
+
 TEST(dash_doesnexist_not_too_hard)
 {
        CHECK(!compopt_too_hard("-doesntexist"));
diff --git a/util.c b/util.c
index 80eb58b6e8d5b2c30e762f836eb944df5ed9ed01..658cab6a94a875d37db66c30796bccfa2e3a7799 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2002 Andrew Tridgell
- * Copyright (C) 2009-2014 Joel Rosdahl
+ * Copyright (C) 2009-2015 Joel Rosdahl
  *
  * 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
@@ -107,16 +107,34 @@ path_max(const char *path)
 #endif
 }
 
+/*
+ * Warn about failure writing to the log file and then exit.
+ */
+static void
+warn_log_fail(void)
+{
+       extern struct conf *conf;
+
+       /* Note: Can't call fatal() since that would lead to recursion. */
+       fprintf(stderr, "ccache: error: Failed to write to %s: %s\n",
+               conf->log_file, strerror(errno));
+       exit(EXIT_FAILURE);
+}
+
 static void
 vlog(const char *format, va_list ap, bool log_updated_time)
 {
+       int rc1, rc2;
        if (!init_log()) {
                return;
        }
 
        log_prefix(log_updated_time);
-       vfprintf(logfile, format, ap);
-       fprintf(logfile, "\n");
+       rc1 = vfprintf(logfile, format, ap);
+       rc2 = fprintf(logfile, "\n");
+       if (rc1 < 0 || rc2 < 0) {
+               warn_log_fail();
+       }
 }
 
 /*
@@ -153,6 +171,7 @@ cc_bulklog(const char *format, ...)
 void
 cc_log_argv(const char *prefix, char **argv)
 {
+       int rc;
        if (!init_log()) {
                return;
        }
@@ -160,7 +179,9 @@ cc_log_argv(const char *prefix, char **argv)
        log_prefix(true);
        fputs(prefix, logfile);
        print_command(logfile, argv);
-       fflush(logfile);
+       rc = fflush(logfile);
+       if (rc)
+               warn_log_fail();
 }
 
 /* something went badly wrong! */
@@ -240,7 +261,8 @@ get_umask(void)
 
 /*
  * Copy src to dest, decompressing src if needed. compress_level > 0 decides
- * whether dest will be compressed, and with which compression level.
+ * whether dest will be compressed, and with which compression level. Returns 0
+ * on success and -1 on failure. On failure, errno represents the error.
  */
 int
 copy_file(const char *src, const char *dest, int compress_level)
@@ -252,6 +274,7 @@ copy_file(const char *src, const char *dest, int compress_level)
        char *tmp_name;
        struct stat st;
        int errnum;
+       int saved_errno = 0;
 
        /* open destination file */
        tmp_name = x_strdup(dest);
@@ -262,13 +285,15 @@ copy_file(const char *src, const char *dest, int compress_level)
        /* open source file */
        fd_in = open(src, O_RDONLY | O_BINARY);
        if (fd_in == -1) {
-               cc_log("open error: %s", strerror(errno));
+               saved_errno = errno;
+               cc_log("open error: %s", strerror(saved_errno));
                goto error;
        }
 
        gz_in = gzdopen(fd_in, "rb");
        if (!gz_in) {
-               cc_log("gzdopen(src) error: %s", strerror(errno));
+               saved_errno = errno;
+               cc_log("gzdopen(src) error: %s", strerror(saved_errno));
                close(fd_in);
                goto error;
        }
@@ -279,8 +304,7 @@ copy_file(const char *src, const char *dest, int compress_level)
                 * occupy an entire filesystem block, even for empty files.
                 * Turn off compression for empty files to save some space.
                 */
-               if (fstat(fd_in, &st) != 0) {
-                       cc_log("fstat error: %s", strerror(errno));
+               if (x_fstat(fd_in, &st) != 0) {
                        goto error;
                }
                if (file_size(&st) == 0) {
@@ -291,7 +315,8 @@ copy_file(const char *src, const char *dest, int compress_level)
        if (compress_level > 0) {
                gz_out = gzdopen(dup(fd_out), "wb");
                if (!gz_out) {
-                       cc_log("gzdopen(dest) error: %s", strerror(errno));
+                       saved_errno = errno;
+                       cc_log("gzdopen(dest) error: %s", strerror(saved_errno));
                        goto error;
                }
                gzsetparams(gz_out, compress_level, Z_DEFAULT_STRATEGY);
@@ -306,6 +331,7 @@ copy_file(const char *src, const char *dest, int compress_level)
                        do {
                                count = write(fd_out, buf + written, n - written);
                                if (count == -1 && errno != EINTR) {
+                                       saved_errno = errno;
                                        break;
                                }
                                written += count;
@@ -315,9 +341,9 @@ copy_file(const char *src, const char *dest, int compress_level)
                        if (compress_level > 0) {
                                cc_log("gzwrite error: %s (errno: %s)",
                                       gzerror(gz_in, &errnum),
-                                      strerror(errno));
+                                      strerror(saved_errno));
                        } else {
-                               cc_log("write error: %s", strerror(errno));
+                               cc_log("write error: %s", strerror(saved_errno));
                        }
                        goto error;
                }
@@ -329,8 +355,9 @@ copy_file(const char *src, const char *dest, int compress_level)
         */
        gzerror(gz_in, &errnum);
        if (!gzeof(gz_in) || (errnum != Z_OK && errnum != Z_STREAM_END)) {
+               saved_errno = errno;
                cc_log("gzread error: %s (errno: %s)",
-                      gzerror(gz_in, &errnum), strerror(errno));
+                      gzerror(gz_in, &errnum), strerror(saved_errno));
                gzclose(gz_in);
                if (gz_out) {
                        gzclose(gz_out);
@@ -354,12 +381,14 @@ copy_file(const char *src, const char *dest, int compress_level)
 
        /* the close can fail on NFS if out of space */
        if (close(fd_out) == -1) {
-               cc_log("close error: %s", strerror(errno));
+               saved_errno = errno;
+               cc_log("close error: %s", strerror(saved_errno));
                goto error;
        }
 
        if (x_rename(tmp_name, dest) == -1) {
-               cc_log("rename error: %s", strerror(errno));
+               saved_errno = errno;
+               cc_log("rename error: %s", strerror(saved_errno));
                goto error;
        }
 
@@ -379,6 +408,7 @@ error:
        }
        tmp_unlink(tmp_name);
        free(tmp_name);
+       errno = saved_errno;
        return -1;
 }
 
@@ -494,16 +524,74 @@ create_parent_dirs(const char *path)
 const char *
 get_hostname(void)
 {
-       static char hostname[200] = "";
+       static char hostname[260] = "";
+
+       if (hostname[0]) {
+               return hostname;
+       }
 
-       if (!hostname[0]) {
-               strcpy(hostname, "unknown");
+       strcpy(hostname, "unknown");
 #if HAVE_GETHOSTNAME
-               gethostname(hostname, sizeof(hostname)-1);
-#endif
-               hostname[sizeof(hostname)-1] = 0;
+       gethostname(hostname, sizeof(hostname) - 1);
+#elif defined(_WIN32)
+       const char *computer_name = getenv("COMPUTERNAME");
+       if (computer_name) {
+               snprintf(hostname, sizeof(hostname), "%s", computer_name);
+               return hostname;
+       }
+
+       WORD wVersionRequested;
+       WSADATA wsaData;
+       int err;
+
+       wVersionRequested = MAKEWORD(2, 2);
+
+       err = WSAStartup(wVersionRequested, &wsaData);
+       if (err != 0) {
+               /* Tell the user that we could not find a usable Winsock DLL. */
+               cc_log("WSAStartup failed with error: %d", err);
+               return hostname;
+       }
+
+       if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
+               /* Tell the user that we could not find a usable WinSock DLL. */
+               cc_log("Could not find a usable version of Winsock.dll");
+               WSACleanup();
+               return hostname;
        }
 
+       int result = gethostname(hostname, sizeof(hostname) - 1);
+       if (result != 0) {
+               int last_error = WSAGetLastError();
+               LPVOID lpMsgBuf;
+               LPVOID lpDisplayBuf;
+               DWORD dw = last_error;
+
+               FormatMessage(
+                       FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                       FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS,
+                       NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                       (LPTSTR) &lpMsgBuf, 0, NULL);
+
+               lpDisplayBuf = (LPVOID) LocalAlloc(
+                       LMEM_ZEROINIT,
+                       (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) __FILE__) + 200)
+                       * sizeof(TCHAR));
+               _snprintf((LPTSTR) lpDisplayBuf,
+                         LocalSize(lpDisplayBuf) / sizeof(TCHAR),
+                         TEXT("%s failed with error %d: %s"), __FILE__, dw,
+                         lpMsgBuf);
+
+               cc_log("can't get hostname OS returned error: %s", (char*)lpDisplayBuf);
+
+               LocalFree(lpMsgBuf);
+               LocalFree(lpDisplayBuf);
+       }
+       WSACleanup();
+#endif
+
+       hostname[sizeof(hostname) - 1] = 0;
        return hostname;
 }
 
@@ -712,6 +800,39 @@ void x_unsetenv(const char *name)
 #endif
 }
 
+/* Like fstat() but also call cc_log on failure. */
+int
+x_fstat(int fd, struct stat *buf)
+{
+       int result = fstat(fd, buf);
+       if (result != 0) {
+               cc_log("Failed to fstat fd %d: %s", fd, strerror(errno));
+       }
+       return result;
+}
+
+/* Like lstat() but also call cc_log on failure. */
+int
+x_lstat(const char *pathname, struct stat *buf)
+{
+       int result = lstat(pathname, buf);
+       if (result != 0) {
+               cc_log("Failed to lstat %s: %s", pathname, strerror(errno));
+       }
+       return result;
+}
+
+/* Like stat() but also call cc_log on failure. */
+int
+x_stat(const char *pathname, struct stat *buf)
+{
+       int result = stat(pathname, buf);
+       if (result != 0) {
+               cc_log("Failed to stat %s: %s", pathname, strerror(errno));
+       }
+       return result;
+}
+
 /*
  * Construct a string according to the format and store it in *ptr. The
  * original *ptr is then freed.
@@ -769,7 +890,7 @@ traverse(const char *dir, void (*fn)(const char *, struct stat *))
                fname = format("%s/%s", dir, de->d_name);
                if (lstat(fname, &st)) {
                        if (errno != ENOENT) {
-                               perror(fname);
+                               fatal("lstat %s failed: %s", fname, strerror(errno));
                        }
                        free(fname);
                        continue;
@@ -986,9 +1107,14 @@ x_realpath(const char *path)
        path_handle = CreateFile(
                path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL, NULL);
-       GetFinalPathNameByHandle(path_handle, ret, maxlen, FILE_NAME_NORMALIZED);
-       CloseHandle(path_handle);
-       p = ret+4;// strip the \\?\ from the file name
+       if (INVALID_HANDLE_VALUE != path_handle) {
+               GetFinalPathNameByHandle(path_handle, ret, maxlen, FILE_NAME_NORMALIZED);
+               CloseHandle(path_handle);
+               p = ret + 4; /* strip \\?\ from the file name */
+       } else {
+               snprintf(ret, maxlen, "%s", path);
+               p = ret;
+       }
 #else
        /* yes, there are such systems. This replacement relies on
           the fact that when we call x_realpath we only care about symlinks */
@@ -1301,14 +1427,46 @@ update_mtime(const char *path)
 /*
  * Rename oldpath to newpath (deleting newpath).
  */
+
 int
 x_rename(const char *oldpath, const char *newpath)
 {
-#ifdef _WIN32
+#ifndef _WIN32
+       return rename(oldpath, newpath);
+#else
        /* Windows' rename() refuses to overwrite an existing file. */
        unlink(newpath);  /* not x_unlink, as x_unlink calls x_rename */
+       /* If the function succeeds, the return value is nonzero. */
+       if (MoveFileA(oldpath, newpath) == 0) {
+               LPVOID lpMsgBuf;
+               LPVOID lpDisplayBuf;
+               DWORD dw = GetLastError();
+
+               FormatMessage(
+                       FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                       FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS,
+                       NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,
+                       0, NULL);
+
+               lpDisplayBuf = (LPVOID) LocalAlloc(
+                       LMEM_ZEROINIT,
+                       (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) __FILE__) + 40)
+                       * sizeof(TCHAR));
+               _snprintf((LPTSTR) lpDisplayBuf,
+                         LocalSize(lpDisplayBuf) / sizeof(TCHAR),
+                         TEXT("%s failed with error %d: %s"), __FILE__, dw, lpMsgBuf);
+
+               cc_log("can't rename file %s to %s OS returned error: %s",
+                      oldpath, newpath, (char*) lpDisplayBuf);
+
+               LocalFree(lpMsgBuf);
+               LocalFree(lpDisplayBuf);
+               return -1;
+       } else {
+               return 0;
+       }
 #endif
-       return rename(oldpath, newpath);
 }
 
 /*
@@ -1318,8 +1476,13 @@ x_rename(const char *oldpath, const char *newpath)
 int
 tmp_unlink(const char *path)
 {
+       int rc;
        cc_log("Unlink %s", path);
-       return unlink(path);
+       rc = unlink(path);
+       if (rc) {
+               cc_log("Unlink failed: %s", strerror(errno));
+       }
+       return rc;
 }
 
 /*
@@ -1335,19 +1498,26 @@ x_unlink(const char *path)
         */
        char *tmp_name = format("%s.rm.%s", path, tmp_string());
        int result = 0;
+       int saved_errno = 0;
        cc_log("Unlink %s via %s", path, tmp_name);
        if (x_rename(path, tmp_name) == -1) {
                result = -1;
+               saved_errno = errno;
                goto out;
        }
        if (unlink(tmp_name) == -1) {
                /* If it was released in a race, that's OK. */
                if (errno != ENOENT) {
                        result = -1;
+                       saved_errno = errno;
                }
        }
 out:
        free(tmp_name);
+       if (result) {
+               cc_log("x_unlink failed: %s", strerror(saved_errno));
+       }
+       errno = saved_errno;
        return result;
 }
 
@@ -1383,7 +1553,7 @@ read_file(const char *path, size_t size_hint, char **data, size_t *size)
 
        if (size_hint == 0) {
                struct stat st;
-               if (stat(path, &st) == 0) {
+               if (x_stat(path, &st) == 0) {
                        size_hint = st.st_size;
                }
        }
index 4bf7d25f506b40e505796141af0b59f0b9b8d610..ec85c8429617028c8e8584dd50301a82a1cd80ff 100644 (file)
--- a/version.c
+++ b/version.c
@@ -1 +1 @@
-const char CCACHE_VERSION[] = "3.2.1";
+const char CCACHE_VERSION[] = "3.2.2";