<body class="article">\r
<div id="header">\r
<h1>ccache copyright and license</h1>\r
-<span id="revnumber">version 3.7.7</span>\r
+<span id="revnumber">version 3.7.8</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>
<div id="footnotes"><hr /></div>\r
<div id="footer">\r
<div id="footer-text">\r
-Version 3.7.7<br />\r
+Version 3.7.8<br />\r
Last updated\r
- 2020-01-05 21:09:39 CET\r
+ 2020-03-16 21:59:40 CET\r
</div>\r
</div>\r
</body>\r
.PHONY: update-authors
update-authors:
- git log --pretty=format:"%H %aN" \
- | grep -Ev 'd7c5056beda5483fcd5c098165fffd9be86fe98d' \
- | sed -r 's/[^ ]+/*/' \
+ git log --pretty=format:"%H %aN%n%(trailers:only)" \
+ | grep -Ev 'd7c5056beda5483fcd5c098165fffd9be86fe98d|http|Conflicts:' \
+ | grep '^[^ ]' \
+ | sed -r -e 's/[^ ]+/*/' -e 's/<.*//' -e 's/ *$$//' \
| sort -u \
| perl -00 -p -i -e 's/^\*.*/<STDIN> . "\n"/es' doc/AUTHORS.adoc
* Andrea Bittau
* Andreas Huber
* André Klitzing
-* Andrew P Boie
+* Andrew Boie
* Andrew Stubbs
* Andrew Tridgell
* Bernhard Bauer
* RW
* Ryan Brown
* Sam Gross
+* Steffen Dettmer
* Thomas Otto
* Thomas Röfer
* Timofei Kushnir
<body class="article">\r
<div id="header">\r
<h1>ccache authors</h1>\r
-<span id="revnumber">version 3.7.7</span>\r
+<span id="revnumber">version 3.7.8</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>
</li>\r
<li>\r
<p>\r
-Andrew P Boie\r
+Andrew Boie\r
</p>\r
</li>\r
<li>\r
</li>\r
<li>\r
<p>\r
+Steffen Dettmer\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Thomas Otto\r
</p>\r
</li>\r
<div id="footnotes"><hr /></div>\r
<div id="footer">\r
<div id="footer-text">\r
-Version 3.7.7<br />\r
+Version 3.7.8<br />\r
Last updated\r
- 2020-01-05 21:09:39 CET\r
+ 2020-03-16 21:59:40 CET\r
</div>\r
</div>\r
</body>\r
Ignore ctimes when *file_stat_matches* is enabled. This can be useful when
backdating files' mtimes in a controlled way.
*include_file_ctime*::
- By default, ccache also will not cache a file if it includes a header whose
+ By default, ccache will not cache a file if it includes a header whose
ctime is too new. This option disables that check.
*include_file_mtime*::
By default, ccache will not cache a file if it includes a header whose
setting.
** A modification time of one of the include files is too new (created the same
second as the compilation is being done). This check is made to avoid a race
- condition. To fix this, create the include file earlier in the build
- process, if possible, or set *sloppiness* to *include_file_mtime* if you are
- willing to take the risk. (The race condition consists of these events: the
- preprocessor is run; an include file is modified by someone; the new include
- file is hashed by ccache; the real compiler is run on the preprocessor's
- output, which contains data from the old header file; the wrong object file
- is stored in the cache.)
+ condition. To fix this, create the include file earlier in the build process,
+ if possible, or set *sloppiness* to *include_file_ctime, include_file_mtime*
+ if you are willing to take the risk. (The race condition consists of these
+ events: the preprocessor is run; an include file is modified by someone; the
+ new include file is hashed by ccache; the real compiler is run on the
+ preprocessor's output, which contains data from the old header file; the
+ wrong object file is stored in the cache.)
** The `__TIME__` preprocessor macro is (potentially) being used. ccache turns
off direct mode if `__TIME__` is present in the source code. This is done as
a safety measure since the string indicates that a `__TIME__` macro _may_
<body class="article">\r
<div id="header">\r
<h1>CCACHE(1)</h1>\r
-<span id="revnumber">version 3.7.7</span>\r
+<span id="revnumber">version 3.7.8</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>
</dt>\r
<dd>\r
<p>\r
- By default, ccache also will not cache a file if it includes a header whose\r
+ By default, ccache will not cache a file if it includes a header whose\r
ctime is too new. This option disables that check.\r
</p>\r
</dd>\r
<p>\r
A modification time of one of the include files is too new (created the same\r
second as the compilation is being done). This check is made to avoid a race\r
- condition. To fix this, create the include file earlier in the build\r
- process, if possible, or set <strong>sloppiness</strong> to <strong>include_file_mtime</strong> if you are\r
- willing to take the risk. (The race condition consists of these events: the\r
- preprocessor is run; an include file is modified by someone; the new include\r
- file is hashed by ccache; the real compiler is run on the preprocessor’s\r
- output, which contains data from the old header file; the wrong object file\r
- is stored in the cache.)\r
+ condition. To fix this, create the include file earlier in the build process,\r
+ if possible, or set <strong>sloppiness</strong> to <strong>include_file_ctime, include_file_mtime</strong>\r
+ if you are willing to take the risk. (The race condition consists of these\r
+ events: the preprocessor is run; an include file is modified by someone; the\r
+ new include file is hashed by ccache; the real compiler is run on the\r
+ preprocessor’s output, which contains data from the old header file; the\r
+ wrong object file is stored in the cache.)\r
</p>\r
</li>\r
<li>\r
<div id="footnotes"><hr /></div>\r
<div id="footer">\r
<div id="footer-text">\r
-Version 3.7.7<br />\r
+Version 3.7.8<br />\r
Last updated\r
- 2020-01-05 21:09:39 CET\r
+ 2020-03-16 21:59:40 CET\r
</div>\r
</div>\r
</body>\r
ccache news
===========
+ccache 3.7.8
+------------
+Release date: 2020-03-16
+
+Bug fixes
+~~~~~~~~~
+
+- Use `$PWD` instead of the real CWD (current working directory) when checking
+ for CWD in preprocessed output. This fixes a problem when `$PWD` includes a
+ symlink part and the user has set `hash_dir = false`.
+
+- Rewrote the Windows version of the lockfile routines. This should mitigate
+ several problems with the old implementation.
+
+- If `localtime_r` fails the epoch time is now logged instead of garbage.
+
+
+Other
+~~~~~
+
+- Improved error message when a boolean environment variable has an invalid
+ value.
+
+- Improved the regression fix in ccache 3.7.5 related to not passing
+ compilation-only options to the preprocessor.
+
+- ccache’s PCH test suite now skips running the tests if it detects broken PCH
+ compiler support.
+
+- Fixed unit test failure on Windows.
+
+- Fixed “stringop-truncation” build warning on Windows.
+
+- Improved “x_rename” implementation on Windows.
+
+- Improved removal of temporary file when rewriting absolute paths to relative
+ in the dependency file.
+
+- Clarified “include_file_ctime sloppiness” in the Performance section in the
+ manual.
+
+
+
ccache 3.7.7
------------
Release date: 2020-01-05
<body class="article">\r
<div id="header">\r
<h1>ccache news</h1>\r
-<span id="revnumber">version 3.7.7</span>\r
+<span id="revnumber">version 3.7.8</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>
</div>\r
<div id="content">\r
<div class="sect1">\r
+<h2 id="_ccache_3_7_8">ccache 3.7.8</h2>\r
+<div class="sectionbody">\r
+<div class="paragraph"><p>Release date: 2020-03-16</p></div>\r
+<div class="sect2">\r
+<h3 id="_bug_fixes">Bug fixes</h3>\r
+<div class="ulist"><ul>\r
+<li>\r
+<p>\r
+Use <code>$PWD</code> instead of the real CWD (current working directory) when checking\r
+ for CWD in preprocessed output. This fixes a problem when <code>$PWD</code> includes a\r
+ symlink part and the user has set <code>hash_dir = false</code>.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Rewrote the Windows version of the lockfile routines. This should mitigate\r
+ several problems with the old implementation.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+If <code>localtime_r</code> fails the epoch time is now logged instead of garbage.\r
+</p>\r
+</li>\r
+</ul></div>\r
+</div>\r
+<div class="sect2">\r
+<h3 id="_other">Other</h3>\r
+<div class="ulist"><ul>\r
+<li>\r
+<p>\r
+Improved error message when a boolean environment variable has an invalid\r
+ value.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Improved the regression fix in ccache 3.7.5 related to not passing\r
+ compilation-only options to the preprocessor.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+ccache’s PCH test suite now skips running the tests if it detects broken PCH\r
+ compiler support.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Fixed unit test failure on Windows.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Fixed “stringop-truncation” build warning on Windows.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Improved “x_rename” implementation on Windows.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Improved removal of temporary file when rewriting absolute paths to relative\r
+ in the dependency file.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Clarified “include_file_ctime sloppiness” in the Performance section in the\r
+ manual.\r
+</p>\r
+</li>\r
+</ul></div>\r
+</div>\r
+</div>\r
+</div>\r
+<div class="sect1">\r
<h2 id="_ccache_3_7_7">ccache 3.7.7</h2>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2020-01-05</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
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2019-11-17</p></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
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_3">Bug fixes</h3>\r
+<h3 id="_bug_fixes_4">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2019-08-17</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_4">Bug fixes</h3>\r
+<h3 id="_bug_fixes_5">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2019-07-19</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_5">Bug fixes</h3>\r
+<h3 id="_bug_fixes_6">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2018-09-02</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_6">Bug fixes</h3>\r
+<h3 id="_bug_fixes_7">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2018-03-25</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_7">Bug fixes</h3>\r
+<h3 id="_bug_fixes_8">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2018-02-11</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_8">Bug fixes</h3>\r
+<h3 id="_bug_fixes_9">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_9">Bug fixes</h3>\r
+<h3 id="_bug_fixes_10">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_10">Bug fixes</h3>\r
+<h3 id="_bug_fixes_11">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_11">Bug fixes</h3>\r
+<h3 id="_bug_fixes_12">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_12">Bug fixes</h3>\r
+<h3 id="_bug_fixes_13">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2016-10-26</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_13">Bug fixes</h3>\r
+<h3 id="_bug_fixes_14">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2016-09-28</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_14">Bug fixes</h3>\r
+<h3 id="_bug_fixes_15">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2016-09-07</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_15">Bug fixes</h3>\r
+<h3 id="_bug_fixes_16">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_16">Bug fixes</h3>\r
+<h3 id="_bug_fixes_17">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2016-09-28</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_17">Bug fixes</h3>\r
+<h3 id="_bug_fixes_18">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2016-09-07</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_18">Bug fixes</h3>\r
+<h3 id="_bug_fixes_19">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2016-07-20</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_19">Bug fixes</h3>\r
+<h3 id="_bug_fixes_20">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2016-07-12</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_20">Bug fixes</h3>\r
+<h3 id="_bug_fixes_21">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_21">Bug fixes</h3>\r
+<h3 id="_bug_fixes_22">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2015-10-08</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_22">Bug fixes</h3>\r
+<h3 id="_bug_fixes_23">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_23">Bug fixes</h3>\r
+<h3 id="_bug_fixes_24">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_24">Bug fixes</h3>\r
+<h3 id="_bug_fixes_25">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\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_25">Bug fixes</h3>\r
+<h3 id="_bug_fixes_26">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_26">Bug fixes</h3>\r
+<h3 id="_bug_fixes_27">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2016-07-12</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_27">Bug fixes</h3>\r
+<h3 id="_bug_fixes_28">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\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_28">Bug fixes</h3>\r
+<h3 id="_bug_fixes_29">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_29">Bug fixes</h3>\r
+<h3 id="_bug_fixes_30">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2013-01-06</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_30">Bug fixes</h3>\r
+<h3 id="_bug_fixes_31">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_other">Other</h3>\r
+<h3 id="_other_2">Other</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_31">Bug fixes</h3>\r
+<h3 id="_bug_fixes_32">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_other_2">Other</h3>\r
+<h3 id="_other_3">Other</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2012-01-08</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_32">Bug fixes</h3>\r
+<h3 id="_bug_fixes_33">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_other_3">Other</h3>\r
+<h3 id="_other_4">Other</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_33">Bug fixes</h3>\r
+<h3 id="_bug_fixes_34">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_34">Bug fixes</h3>\r
+<h3 id="_bug_fixes_35">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2011-01-09</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_35">Bug fixes</h3>\r
+<h3 id="_bug_fixes_36">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2010-11-28</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_36">Bug fixes</h3>\r
+<h3 id="_bug_fixes_37">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_other_4">Other</h3>\r
+<h3 id="_other_5">Other</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2010-11-21</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_37">Bug fixes</h3>\r
+<h3 id="_bug_fixes_38">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_other_5">Other</h3>\r
+<h3 id="_other_6">Other</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2010-11-07</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_38">Bug fixes</h3>\r
+<h3 id="_bug_fixes_39">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_other_6">Other</h3>\r
+<h3 id="_other_7">Other</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_39">Bug fixes</h3>\r
+<h3 id="_bug_fixes_40">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_other_7">Other</h3>\r
+<h3 id="_other_8">Other</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2010-07-15</p></div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_40">Bug fixes</h3>\r
+<h3 id="_bug_fixes_41">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes_41">Bug fixes</h3>\r
+<h3 id="_bug_fixes_42">Bug fixes</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<div id="footnotes"><hr /></div>\r
<div id="footer">\r
<div id="footer-text">\r
-Version 3.7.7<br />\r
+Version 3.7.8<br />\r
Last updated\r
- 2020-01-05 21:09:39 CET\r
+ 2020-03-16 21:59:40 CET\r
</div>\r
</div>\r
</body>\r
.\" Title: ccache
.\" Author: [see the "Author" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\" Date: 01/05/2020
+.\" Date: 03/16/2020
.\" Manual: ccache Manual
-.\" Source: ccache 3.7.7
+.\" Source: ccache 3.7.8
.\" Language: English
.\"
-.TH "CCACHE" "1" "01/05/2020" "ccache 3\&.7\&.7" "ccache Manual"
+.TH "CCACHE" "1" "03/16/2020" "ccache 3\&.7\&.8" "ccache Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.PP
\fBinclude_file_ctime\fR
.RS 4
-By default, ccache also will not cache a file if it includes a header whose ctime is too new\&. This option disables that check\&.
+By default, ccache will not cache a file if it includes a header whose ctime is too new\&. This option disables that check\&.
.RE
.PP
\fBinclude_file_mtime\fR
A modification time of one of the include files is too new (created the same second as the compilation is being done)\&. This check is made to avoid a race condition\&. To fix this, create the include file earlier in the build process, if possible, or set
\fBsloppiness\fR
to
-\fBinclude_file_mtime\fR
+\fBinclude_file_ctime, include_file_mtime\fR
if you are willing to take the risk\&. (The race condition consists of these events: the preprocessor is run; an include file is modified by someone; the new include file is hashed by ccache; the real compiler is run on the preprocessor\(cqs output, which contains data from the old header file; the wrong object file is stored in the cache\&.)
.RE
.sp
init_included_files_table();
- char *cwd = gnu_getcwd();
+ char *cwd = get_cwd();
// Bytes between p and q are pending to be hashed.
char *p = data;
}
if (!result) {
cc_log("Removing temporary dependency file: %s", tmp_file);
- x_unlink(tmp_file);
+ tmp_unlink(tmp_file);
}
free(tmp_file);
}
// Possibly hash the current working directory.
if (generating_debuginfo && conf->hash_dir) {
- char *cwd = gnu_getcwd();
+ char *cwd = get_cwd();
for (size_t i = 0; i < debug_prefix_maps_len; i++) {
char *map = debug_prefix_maps[i];
char *sep = strchr(map, '=');
// modes and calculate the object hash. Returns the object hash on success,
// otherwise NULL. Caller frees.
static struct file_hash *
-calculate_object_hash(struct args *args, struct hash *hash, int direct_mode)
+calculate_object_hash(struct args *args, struct args *preprocessor_args,
+ struct hash *hash, int direct_mode)
{
bool found_ccbin = false;
cc_log("Did not find object file hash in manifest");
}
} else {
+ assert(preprocessor_args);
if (arch_args_size == 0) {
- object_hash = get_object_name_from_cpp(args, hash);
+ object_hash = get_object_name_from_cpp(preprocessor_args, hash);
cc_log("Got object file hash from preprocessor");
} else {
- args_add(args, "-arch");
+ args_add(preprocessor_args, "-arch");
for (size_t i = 0; i < arch_args_size; ++i) {
- args_add(args, arch_args[i]);
- object_hash = get_object_name_from_cpp(args, hash);
+ args_add(preprocessor_args, arch_args[i]);
+ object_hash = get_object_name_from_cpp(preprocessor_args, hash);
cc_log("Got object file hash from preprocessor with -arch %s",
arch_args[i]);
if (i != arch_args_size - 1) {
free(object_hash);
object_hash = NULL;
}
- args_pop(args, 1);
+ args_pop(preprocessor_args, 1);
}
- args_pop(args, 1);
+ args_pop(preprocessor_args, 1);
}
if (generating_dependencies) {
// Nothing is actually created with -MF /dev/null
if (conf->direct_mode) {
cc_log("Trying direct lookup");
MTR_BEGIN("hash", "direct_hash");
- object_hash = calculate_object_hash(args_to_hash, direct_hash, 1);
+ object_hash = calculate_object_hash(args_to_hash, NULL, direct_hash, 1);
MTR_END("hash", "direct_hash");
if (object_hash) {
update_cached_result_globals(object_hash);
cpp_hash, output_obj, 'p', "PREPROCESSOR MODE", debug_text_file);
MTR_BEGIN("hash", "cpp_hash");
- object_hash = calculate_object_hash(args_to_hash, cpp_hash, 0);
+ object_hash = calculate_object_hash(
+ args_to_hash, preprocessor_args, cpp_hash, 0);
MTR_END("hash", "cpp_hash");
if (!object_hash) {
fatal("internal error: object hash from cpp returned NULL");
-// Copyright (C) 2011-2019 Joel Rosdahl
+// Copyright (C) 2011-2020 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
static enum handle_conf_result
handle_conf_setting(struct conf *conf, const char *key, const char *value,
- char **errmsg, bool from_env_variable, bool negate_boolean,
- const char *origin)
+ char **errmsg, const char *env_var_name,
+ bool negate_boolean, const char *origin)
{
const struct conf_item *item = find_conf(key);
if (!item) {
return HANDLE_CONF_UNKNOWN;
}
- if (from_env_variable && item->parser == confitem_parse_bool) {
+ if (env_var_name && item->parser == confitem_parse_bool) {
// Special rule for boolean settings from the environment: "0", "false",
// "disable" and "no" (case insensitive) are invalid, and all other values
// mean true.
// enabled.
if (str_eq(value, "0") || strcasecmp(value, "false") == 0
|| strcasecmp(value, "disable") == 0 || strcasecmp(value, "no") == 0) {
- fatal("invalid boolean environment variable value \"%s\"", value);
+ fatal(
+ "invalid boolean environment variable value \"%s\" for CCACHE_%s%s"
+ " (did you mean to set \"CCACHE_%s%s=true\"?)",
+ value,
+ negate_boolean ? "NO" : "",
+ env_var_name, negate_boolean ? "" : "NO",
+ env_var_name);
}
bool *boolvalue = (bool *)((char *)conf + item->offset);
bool ok = parse_line(buf, &key, &value, &errmsg2);
if (ok && key) { // key == NULL if comment or blank line.
hcr =
- handle_conf_setting(conf, key, value, &errmsg2, false, false, path);
+ handle_conf_setting(conf, key, value, &errmsg2, NULL, false, path);
ok = hcr != HANDLE_CONF_FAIL; // unknown is OK
}
free(key);
char *errmsg2 = NULL;
enum handle_conf_result hcr = handle_conf_setting(
- conf, env_to_conf_item->conf_name, q, &errmsg2, true, negate,
- "environment");
+ conf, env_to_conf_item->conf_name, q, &errmsg2,
+ env_to_conf_item->env_name, negate, "environment");
if (hcr != HANDLE_CONF_OK) {
*errmsg = format("%s: %s", key, errmsg2);
free(errmsg2);
-// Copyright (C) 2010-2018 Joel Rosdahl
+// Copyright (C) 2010-2020 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
#include "ccache.h"
+#ifndef _WIN32
+
// This function acquires a lockfile for the given path. Returns true if the
// lock was acquired, otherwise false. If the lock has been considered stale
// for the number of microseconds specified by staleness_limit, the function
const char *hostname = get_hostname();
bool acquired = false;
unsigned to_sleep = 1000; // Microseconds.
+ unsigned max_to_sleep = 10000; // Microseconds.
unsigned slept = 0; // Microseconds.
while (true) {
free(my_content);
my_content = format("%s:%d:%d", hostname, (int)getpid(), (int)time(NULL));
-#ifdef _WIN32
- int fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0666);
- if (fd == -1) {
- int saved_errno = errno;
- cc_log("lockfile_acquire: open WRONLY %s: %s", lockfile, strerror(errno));
- if (saved_errno == ENOENT) {
- // Directory doesn't exist?
- if (create_parent_dirs(lockfile) == 0) {
- // OK. Retry.
- continue;
- }
- }
- if (saved_errno != EEXIST) {
- // Directory doesn't exist or isn't writable?
- goto out;
- }
- // Someone else has the lock.
- fd = open(lockfile, O_RDONLY|O_BINARY);
- if (fd == -1) {
- if (errno == ENOENT) {
- // The file was removed after the open() call above, so retry
- // acquiring it.
- continue;
- } else {
- cc_log("lockfile_acquire: open RDONLY %s: %s",
- lockfile, strerror(errno));
- goto out;
- }
- }
- free(content);
- const size_t bufsize = 1024;
- content = x_malloc(bufsize);
- int len = read(fd, content, bufsize - 1);
- if (len == -1) {
- cc_log("lockfile_acquire: read %s: %s", lockfile, strerror(errno));
- close(fd);
- goto out;
- }
- close(fd);
- content[len] = '\0';
- } else {
- // We got the lock.
- if (write(fd, my_content, strlen(my_content)) == -1) {
- cc_log("lockfile_acquire: write %s: %s", lockfile, strerror(errno));
- close(fd);
- x_unlink(lockfile);
- goto out;
- }
- close(fd);
- acquired = true;
- goto out;
- }
-#else
if (symlink(my_content, lockfile) == 0) {
// We got the lock.
acquired = true;
goto out;
}
}
-#endif
if (str_eq(content, my_content)) {
// Lost NFS reply?
lockfile, to_sleep);
usleep(to_sleep);
slept += to_sleep;
- to_sleep *= 2;
+ to_sleep = MIN(max_to_sleep, 2 * to_sleep);
}
out:
free(lockfile);
}
+#else
+
+HANDLE lockfile_handle = NULL;
+
+// This function acquires a lockfile for the given path. Returns true if the
+// lock was acquired, otherwise false. If the lock has been acquired within the
+// limit (in microseconds) the function will give up and return false. The time
+// limit should be reasonably larger than the longest time the lock can be
+// expected to be held.
+bool
+lockfile_acquire(const char *path, unsigned time_limit)
+{
+ char *lockfile = format("%s.lock", path);
+ unsigned to_sleep = 1000; // Microseconds.
+ unsigned max_to_sleep = 10000; // Microseconds.
+ unsigned slept = 0; // Microseconds.
+ bool acquired = false;
+
+ while (true) {
+ DWORD flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE;
+ lockfile_handle = CreateFile(
+ lockfile,
+ GENERIC_WRITE, // desired access
+ 0, // shared mode (0 = not shared)
+ NULL, // security attributes
+ CREATE_ALWAYS, // creation disposition,
+ flags, // flags and attributes
+ NULL // template file
+ );
+ if (lockfile_handle != INVALID_HANDLE_VALUE) {
+ acquired = true;
+ break;
+ }
+
+ DWORD error = GetLastError();
+ cc_log("lockfile_acquire: CreateFile %s: error code %lu", lockfile, error);
+ if (error == ERROR_PATH_NOT_FOUND) {
+ // Directory doesn't exist?
+ if (create_parent_dirs(lockfile) == 0) {
+ // OK. Retry.
+ continue;
+ }
+ }
+
+ // ERROR_SHARING_VIOLATION: lock already held.
+ // ERROR_ACCESS_DENIED: maybe pending delete.
+ if (error != ERROR_SHARING_VIOLATION && error != ERROR_ACCESS_DENIED) {
+ // Fatal error, give up.
+ break;
+ }
+
+ if (slept > time_limit) {
+ cc_log("lockfile_acquire: gave up acquiring %s", lockfile);
+ break;
+ }
+
+ cc_log("lockfile_acquire: failed to acquire %s; sleeping %u microseconds",
+ lockfile, to_sleep);
+ usleep(to_sleep);
+ slept += to_sleep;
+ to_sleep = MIN(max_to_sleep, 2 * to_sleep);
+ }
+
+ if (acquired) {
+ cc_log("Acquired lock %s", lockfile);
+ } else {
+ cc_log("Failed to acquire lock %s", lockfile);
+ }
+ free(lockfile);
+ return acquired;
+}
+
+// Release the lockfile for the given path. Assumes that we are the legitimate
+// owner.
+void
+lockfile_release(const char *path)
+{
+ assert(lockfile_handle != INVALID_HANDLE_VALUE);
+ cc_log("Releasing lock %s.lock", path);
+ CloseHandle(lockfile_handle);
+ lockfile_handle = NULL;
+}
+
+#endif
+
#ifdef TEST_LOCKFILE
+
int
main(int argc, char **argv)
{
- extern char *cache_logfile;
- cache_logfile = "/dev/stdout";
- if (argc == 4) {
+ extern struct conf *conf;
+ conf = conf_create();
+ if (argc == 3) {
unsigned staleness_limit = atoi(argv[1]);
- if (str_eq(argv[2], "acquire")) {
- return lockfile_acquire(argv[3], staleness_limit) == 0;
- } else if (str_eq(argv[2], "release")) {
- lockfile_release(argv[3]);
- return 0;
+ printf("Acquiring\n");
+ bool acquired = lockfile_acquire(argv[2], staleness_limit);
+ if (acquired) {
+ printf("Sleeping 2 seconds\n");
+ sleep(2);
+ lockfile_release(argv[2]);
+ printf("Released\n");
+ } else {
+ printf("Failed to acquire\n");
}
+ } else {
+ fprintf(stderr,
+ "Usage: testlockfile <staleness_limit> <path>\n");
}
- fprintf(stderr,
- "Usage: testlockfile <staleness_limit> <acquire|release> <path>\n");
return 1;
}
#endif
// Copyright (C) 2002 Andrew Tridgell
-// Copyright (C) 2009-2019 Joel Rosdahl
+// Copyright (C) 2009-2020 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
struct tm tm;
struct timeval tv;
gettimeofday(&tv, NULL);
-#ifdef __MINGW64_VERSION_MAJOR
- localtime_r((time_t *)&tv.tv_sec, &tm);
-#else
- localtime_r(&tv.tv_sec, &tm);
-#endif
- strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", &tm);
+ if (localtime_r((time_t *)&tv.tv_sec, &tm) != NULL) {
+ strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", &tm);
+ } else {
+ snprintf(timestamp, sizeof(timestamp), "%lu", tv.tv_sec);
+ }
snprintf(prefix, sizeof(prefix),
"[%s.%06d %-5d] ", timestamp, (int)tv.tv_usec, (int)getpid());
}
TEXT("%s%s"),
drive,
filename+name_len);
- _tcsncpy(filename, temp_file, _tcslen(temp_file));
+ strcpy(filename, temp_file);
}
}
}
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) {
+ if (MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING) == 0) {
LPVOID lp_msg_buf;
DWORD dw = GetLastError();
FormatMessage(
-extern const char CCACHE_VERSION[]; const char CCACHE_VERSION[] = "3.7.7";
+extern const char CCACHE_VERSION[]; const char CCACHE_VERSION[] = "3.7.8";
# A simple test suite for ccache.
#
# Copyright (C) 2002-2007 Andrew Tridgell
-# Copyright (C) 2009-2019 Joel Rosdahl
+# Copyright (C) 2009-2020 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
cd /
remove_cache
- rm -rf $ABS_TESTDIR/run
- mkdir $ABS_TESTDIR/run
+ rm -rf $ABS_TESTDIR/run $ABS_TESTDIR/run.real
+
+ # Verify that tests behave well when apparent CWD != actual CWD.
+ mkdir $ABS_TESTDIR/run.real
+ ln -s run.real $ABS_TESTDIR/run
+
cd $ABS_TESTDIR/run
if type SUITE_${suite_name}_SETUP >/dev/null 2>&1; then
SUITE_${suite_name}_SETUP
# -------------------------------------------------------------------------
TEST "Handling of compiler-only arguments"
- $CCACHE_COMPILE -c test1.c
+ cat >compiler.sh <<EOF
+#!/bin/sh
+printf "[%s]" "\$*" >>compiler.args
+[ \$1 = -E ] && echo test || echo test >test1.o
+EOF
+ chmod +x compiler.sh
+ backdate compiler.sh
+
+ $CCACHE ./compiler.sh -c test1.c
expect_stat 'cache hit (preprocessed)' 0
expect_stat 'cache miss' 1
expect_stat 'files in cache' 1
+ if [ -z "$CCACHE_NOCPP2" ]; then
+ expect_file_content compiler.args "[-E test1.c][-c -o test1.o test1.c]"
+ fi
+ rm compiler.args
- $CCACHE_COMPILE -c test1.c
+ $CCACHE ./compiler.sh -c test1.c
expect_stat 'cache hit (preprocessed)' 1
expect_stat 'cache miss' 1
expect_stat 'files in cache' 1
+ expect_file_content compiler.args "[-E test1.c]"
+ rm compiler.args
# Even though -Werror is not passed to the preprocessor, it should be part
# of the hash, so we expect a cache miss:
- $CCACHE_COMPILE -c -Werror test1.c
+ $CCACHE ./compiler.sh -c -Werror -rdynamic test1.c
expect_stat 'cache hit (preprocessed)' 1
expect_stat 'cache miss' 2
expect_stat 'files in cache' 2
+ if [ -z "$CCACHE_NOCPP2" ]; then
+ expect_file_content compiler.args "[-E test1.c][-Werror -rdynamic -c -o test1.o test1.c]"
+ fi
+ rm compiler.args
# -------------------------------------------------------------------------
TEST "Dependency file content"
SUITE_pch_PROBE() {
- touch pch.h
+ touch pch.h empty.c
+ mkdir dir
+
if ! $REAL_COMPILER $SYSROOT -fpch-preprocess pch.h 2>/dev/null \
|| [ ! -f pch.h.gch ]; then
- echo "compiler ($($COMPILER --version | head -1)) doesn't support precompiled headers"
+ echo "compiler ($($COMPILER --version | head -n 1)) doesn't support precompiled headers"
+ fi
+
+ $REAL_COMPILER $SYSROOT -c pch.h -o dir/pch.h.gch 2>/dev/null
+ if ! $REAL_COMPILER $SYSROOT -c -include dir/pch.h empty.c 2>/dev/null; then
+ echo "compiler ($($COMPILER --version | head -n 1)) seems to have broken support for precompiled headers"
fi
}
-// Copyright (C) 2010-2018 Joel Rosdahl
+// Copyright (C) 2010-2020 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
CHECK_STR_EQ("fourth", args->argv[3]);
CHECK_STR_EQ("fif th", args->argv[4]);
CHECK_STR_EQ("si'x\" th", args->argv[5]);
-#ifndef _WIN32
CHECK_STR_EQ("seve\nth", args->argv[6]);
-#else
- CHECK_STR_EQ("seve\r\nth", args->argv[6]);
-#endif
CHECK(!args->argv[7]);
args_free(args);
}
-// Copyright (C) 2011-2019 Joel Rosdahl
+// Copyright (C) 2011-2020 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
-// Copyright (C) 2010-2018 Joel Rosdahl
+// Copyright (C) 2010-2020 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
TEST_SUITE(lockfile)
-TEST(acquire_should_create_symlink)
+TEST(acquire_and_release)
{
- lockfile_acquire("test", 1000);
+ CHECK(lockfile_acquire("test", 1000));
#ifdef _WIN32
CHECK(path_exists("test.lock"));
#else
CHECK(is_symlink("test.lock"));
#endif
-}
-TEST(release_should_delete_file)
-{
- create_file("test.lock", "");
lockfile_release("test");
-
CHECK(!path_exists("test.lock"));
}
+#ifndef _WIN32
+
TEST(lock_breaking)
{
char *p;
-#ifdef _WIN32
- create_file("test.lock", "foo");
- create_file("test.lock.lock", "foo");
-#else
CHECK_INT_EQ(0, symlink("foo", "test.lock"));
CHECK_INT_EQ(0, symlink("foo", "test.lock.lock"));
-#endif
CHECK(lockfile_acquire("test", 1000));
-#ifdef _WIN32
- p = read_text_file("test.lock", 0);
-#else
p = x_readlink("test.lock");
-#endif
CHECK(p);
CHECK(!str_eq(p, "foo"));
CHECK(!path_exists("test.lock.lock"));
free(p);
}
-#ifndef _WIN32
TEST(failed_lock_breaking)
{
create_file("test.lock", "");
CHECK(!lockfile_acquire("test", 1000));
}
-#endif
+
+#endif // !_WIN32
TEST_SUITE_END
-// Copyright (C) 2010-2018 Joel Rosdahl
+// Copyright (C) 2010-2020 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
void
create_file(const char *path, const char *content)
{
- FILE *f = fopen(path, "w");
+ FILE *f = fopen(path, "wb");
if (!f || fputs(content, f) < 0) {
fprintf(stderr, "create_file: %s: %s\n", path, strerror(errno));
}