<body class="article">\r
<div id="header">\r
<h1>ccache authors</h1>\r
-<span id="revnumber">version 3.2.9</span>\r
+<span id="revnumber">version 3.3</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
+André Klitzing <<a href="mailto:aklitzing@gmail.com">aklitzing@gmail.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Bernhard Bauer <<a href="mailto:bauerb@chromium.org">bauerb@chromium.org</a>>\r
</p>\r
</li>\r
</li>\r
<li>\r
<p>\r
-Clemens Rabe <<a href="mailto:crabe@gmx.de">crabe@gmx.de</a>>\r
+Clemens Rabe <<a href="mailto:clemens.rabe@gmail.com">clemens.rabe@gmail.com</a>>\r
</p>\r
</li>\r
<li>\r
</li>\r
<li>\r
<p>\r
+Ivan Vaigult <<a href="mailto:i.vaigult@gmail.com">i.vaigult@gmail.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Jiang Jiang <<a href="mailto:jiangj@opera.com">jiangj@opera.com</a>>\r
</p>\r
</li>\r
</li>\r
<li>\r
<p>\r
+John Basila <<a href="mailto:jbasila@checkpoint.com">jbasila@checkpoint.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
John Coiner <<a href="mailto:john.coiner@amd.com">john.coiner@amd.com</a>>\r
</p>\r
</li>\r
</li>\r
<li>\r
<p>\r
+Melven Roehrig-Zoellner <<a href="mailto:Melven.Roehrig-Zoellner@DLR.de">Melven.Roehrig-Zoellner@DLR.de</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Michael Marineau <<a href="mailto:michael.marineau@coreos.com">michael.marineau@coreos.com</a>>\r
</p>\r
</li>\r
</li>\r
<li>\r
<p>\r
+Mihai Serban <<a href="mailto:mihai.serban@intel.com">mihai.serban@intel.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Mike Frysinger <<a href="mailto:vapier@gentoo.org">vapier@gentoo.org</a>>\r
</p>\r
</li>\r
</li>\r
<li>\r
<p>\r
+Norbert Lange <<a href="mailto:nolange79@gmail.com">nolange79@gmail.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Orgad Shaneh <<a href="mailto:orgad.shaneh@audiocodes.com">orgad.shaneh@audiocodes.com</a>>\r
</p>\r
</li>\r
<li>\r
<p>\r
+Orion Poplawski <<a href="mailto:orion@cora.nwra.com">orion@cora.nwra.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Owen Mann <<a href="mailto:owen@mann.org">owen@mann.org</a>>\r
</p>\r
</li>\r
</li>\r
<li>\r
<p>\r
+Pavel Boldin <<a href="mailto:pboldin@cloudlinux.com">pboldin@cloudlinux.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
RW <<a href="mailto:fbsd06@mlists.homeunix.com">fbsd06@mlists.homeunix.com</a>>\r
</p>\r
</li>\r
</li>\r
<li>\r
<p>\r
+Rolf Bjarne Kvinge <<a href="mailto:rolf@xamarin.com">rolf@xamarin.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Ryan Brown <<a href="mailto:ryb@ableton.com">ryb@ableton.com</a>>\r
</p>\r
</li>\r
<div id="footnotes"><hr /></div>\r
<div id="footer">\r
<div id="footer-text">\r
-Version 3.2.9<br />\r
+Version 3.3<br />\r
Last updated\r
- 2016-09-28 21:28:19 CEST\r
+ 2016-08-27 16:54:44 CEST\r
</div>\r
</div>\r
</body>\r
* Andrew P Boie <andrew.p.boie@intel.com>
* Andrew Stubbs <ams@codesourcery.com>
* Andrew Tridgell <tridge@samba.org>
+* André Klitzing <aklitzing@gmail.com>
* 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>
+* Clemens Rabe <clemens.rabe@gmail.com>
* David Givone <david@givone.net>
* Eric Blau <Eric.Blau@tekelec.com>
* Francois Marier <francois@debian.org>
* Hongli Lai <hongli@phusion.nl>
+* Ivan Vaigult <i.vaigult@gmail.com>
* Jiang Jiang <jiangj@opera.com>
* Joel Rosdahl <joel@rosdahl.net>
+* John Basila <jbasila@checkpoint.com>
* John Coiner <john.coiner@amd.com>
* Jon Bernard <jbernard@tuxion.com>
* Justin Lebar <justin.lebar@gmail.com>
* Mark Starovoytov <starovoytov.mark@googlemail.com>
* Martin Pool <mbp@sourcefrog.net>
* Matthias Kretz <kretz@kde.org>
+* Melven Roehrig-Zoellner <Melven.Roehrig-Zoellner@DLR.de>
* Michael Marineau <michael.marineau@coreos.com>
* Michael Meeks <michael.meeks@suse.com>
+* Mihai Serban <mihai.serban@intel.com>
* Mike Frysinger <vapier@gentoo.org>
* Mikhail Kolomeytsev <mkolom@yandex-team.ru>
* Neil Mushell <nmushell@bloomberg.net>
* Nick Schultz <nick.schultz@intel.com>
+* Norbert Lange <nolange79@gmail.com>
* Orgad Shaneh <orgad.shaneh@audiocodes.com>
+* Orion Poplawski <orion@cora.nwra.com>
* Owen Mann <owen@mann.org>
* Patrick von Reth <vonreth@kde.org>
* Paul Griffith <paulg@cse.yorku.ca>
+* Pavel Boldin <pboldin@cloudlinux.com>
* RW <fbsd06@mlists.homeunix.com>
* Ramiro Polla <ramiro.polla@gmail.com>
* Robin H. Johnson <robbat2@gentoo.org>
+* Rolf Bjarne Kvinge <rolf@xamarin.com>
* Ryan Brown <ryb@ableton.com>
* Tim Potter <tpot@samba.org>
* Tor Arne Vestbø <torarnv@gmail.com>
* Use only lowercase names for functions and variables.
* Use only uppercase names for enum items and (with some exceptions) macros.
* Don't use typedefs for structs and enums.
+* Use //-style comments.
Tip: Install the tool uncrustify <http://uncrustify.sourceforge.net> and then
run "make uncrustify" to fix up source code formatting.
Idioms
------
+* Declare variables as late as convenient, not necessarily at the beginning of
+ the scope.
* Use NULL to initialize null pointers.
* Don't use NULL when comparing pointers.
* Use format(), x_malloc() and friends instead of checking for memory
Commit messages
---------------
-* Write a short description on the first line. If wanted, leave the second line
- empty and write a longer description on line three and below.
-* Start the short description with a capital letter. Optional: prefix the short
+* Write a summary (short description) on the first line.
+* Start the summary with a capital letter. Optional: prefix the short
description with a context followed by a colon.
-* The short description should be in "command form" (see examples below).
-* Don't put a final period after the short description.
-* Keep lines in the message at most 75 characters wide.
+* The summary should be in imperative mood (see examples below).
+* The summary should not end with a period. It's a title and titles don't end
+ with a period.
+* If a longer description is wanted, add a second line empty and write the
+ longer description on line three and below.
+* Keep lines in the message at most 72 characters wide.
Example 1:
Hash a delimiter string between parts to separate them
- Previously, "gcc -I-O2 -c file.c" and "gcc -I -O2 -c file.c" would hash to
- the same sum.
+ Previously, "gcc -I-O2 -c file.c" and "gcc -I -O2 -c file.c" would hash
+ to the same sum.
Example 2:
win32: Add a space between filename and error string in x_fmmap()
+
+See also:
+
+* http://stopwritingramblingcommitmessages.com
+* http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
+* https://github.com/erlang/otp/wiki/Writing-good-commit-messages
+++ /dev/null
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"\r
- "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\r
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">\r
-<head>\r
-<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />\r
-<meta name="generator" content="AsciiDoc 8.6.9" />\r
-<title>ccache installation</title>\r
-<style type="text/css">\r
-/* Shared CSS for AsciiDoc xhtml11 and html5 backends */\r
-\r
-/* Default font. */\r
-body {\r
- font-family: Georgia,serif;\r
-}\r
-\r
-/* Title font. */\r
-h1, h2, h3, h4, h5, h6,\r
-div.title, caption.title,\r
-thead, p.table.header,\r
-#toctitle,\r
-#author, #revnumber, #revdate, #revremark,\r
-#footer {\r
- font-family: Arial,Helvetica,sans-serif;\r
-}\r
-\r
-body {\r
- margin: 1em 5% 1em 5%;\r
-}\r
-\r
-a {\r
- color: blue;\r
- text-decoration: underline;\r
-}\r
-a:visited {\r
- color: fuchsia;\r
-}\r
-\r
-em {\r
- font-style: italic;\r
- color: navy;\r
-}\r
-\r
-strong {\r
- font-weight: bold;\r
- color: #083194;\r
-}\r
-\r
-h1, h2, h3, h4, h5, h6 {\r
- color: #527bbd;\r
- margin-top: 1.2em;\r
- margin-bottom: 0.5em;\r
- line-height: 1.3;\r
-}\r
-\r
-h1, h2, h3 {\r
- border-bottom: 2px solid silver;\r
-}\r
-h2 {\r
- padding-top: 0.5em;\r
-}\r
-h3 {\r
- float: left;\r
-}\r
-h3 + * {\r
- clear: left;\r
-}\r
-h5 {\r
- font-size: 1.0em;\r
-}\r
-\r
-div.sectionbody {\r
- margin-left: 0;\r
-}\r
-\r
-hr {\r
- border: 1px solid silver;\r
-}\r
-\r
-p {\r
- margin-top: 0.5em;\r
- margin-bottom: 0.5em;\r
-}\r
-\r
-ul, ol, li > p {\r
- margin-top: 0;\r
-}\r
-ul > li { color: #aaa; }\r
-ul > li > * { color: black; }\r
-\r
-.monospaced, code, pre {\r
- font-family: "Courier New", Courier, monospace;\r
- font-size: inherit;\r
- color: navy;\r
- padding: 0;\r
- margin: 0;\r
-}\r
-pre {\r
- white-space: pre-wrap;\r
-}\r
-\r
-#author {\r
- color: #527bbd;\r
- font-weight: bold;\r
- font-size: 1.1em;\r
-}\r
-#email {\r
-}\r
-#revnumber, #revdate, #revremark {\r
-}\r
-\r
-#footer {\r
- font-size: small;\r
- border-top: 2px solid silver;\r
- padding-top: 0.5em;\r
- margin-top: 4.0em;\r
-}\r
-#footer-text {\r
- float: left;\r
- padding-bottom: 0.5em;\r
-}\r
-#footer-badges {\r
- float: right;\r
- padding-bottom: 0.5em;\r
-}\r
-\r
-#preamble {\r
- margin-top: 1.5em;\r
- margin-bottom: 1.5em;\r
-}\r
-div.imageblock, div.exampleblock, div.verseblock,\r
-div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,\r
-div.admonitionblock {\r
- margin-top: 1.0em;\r
- margin-bottom: 1.5em;\r
-}\r
-div.admonitionblock {\r
- margin-top: 2.0em;\r
- margin-bottom: 2.0em;\r
- margin-right: 10%;\r
- color: #606060;\r
-}\r
-\r
-div.content { /* Block element content. */\r
- padding: 0;\r
-}\r
-\r
-/* Block element titles. */\r
-div.title, caption.title {\r
- color: #527bbd;\r
- font-weight: bold;\r
- text-align: left;\r
- margin-top: 1.0em;\r
- margin-bottom: 0.5em;\r
-}\r
-div.title + * {\r
- margin-top: 0;\r
-}\r
-\r
-td div.title:first-child {\r
- margin-top: 0.0em;\r
-}\r
-div.content div.title:first-child {\r
- margin-top: 0.0em;\r
-}\r
-div.content + div.title {\r
- margin-top: 0.0em;\r
-}\r
-\r
-div.sidebarblock > div.content {\r
- background: #ffffee;\r
- border: 1px solid #dddddd;\r
- border-left: 4px solid #f0f0f0;\r
- padding: 0.5em;\r
-}\r
-\r
-div.listingblock > div.content {\r
- border: 1px solid #dddddd;\r
- border-left: 5px solid #f0f0f0;\r
- background: #f8f8f8;\r
- padding: 0.5em;\r
-}\r
-\r
-div.quoteblock, div.verseblock {\r
- padding-left: 1.0em;\r
- margin-left: 1.0em;\r
- margin-right: 10%;\r
- border-left: 5px solid #f0f0f0;\r
- color: #888;\r
-}\r
-\r
-div.quoteblock > div.attribution {\r
- padding-top: 0.5em;\r
- text-align: right;\r
-}\r
-\r
-div.verseblock > pre.content {\r
- font-family: inherit;\r
- font-size: inherit;\r
-}\r
-div.verseblock > div.attribution {\r
- padding-top: 0.75em;\r
- text-align: left;\r
-}\r
-/* DEPRECATED: Pre version 8.2.7 verse style literal block. */\r
-div.verseblock + div.attribution {\r
- text-align: left;\r
-}\r
-\r
-div.admonitionblock .icon {\r
- vertical-align: top;\r
- font-size: 1.1em;\r
- font-weight: bold;\r
- text-decoration: underline;\r
- color: #527bbd;\r
- padding-right: 0.5em;\r
-}\r
-div.admonitionblock td.content {\r
- padding-left: 0.5em;\r
- border-left: 3px solid #dddddd;\r
-}\r
-\r
-div.exampleblock > div.content {\r
- border-left: 3px solid #dddddd;\r
- padding-left: 0.5em;\r
-}\r
-\r
-div.imageblock div.content { padding-left: 0; }\r
-span.image img { border-style: none; vertical-align: text-bottom; }\r
-a.image:visited { color: white; }\r
-\r
-dl {\r
- margin-top: 0.8em;\r
- margin-bottom: 0.8em;\r
-}\r
-dt {\r
- margin-top: 0.5em;\r
- margin-bottom: 0;\r
- font-style: normal;\r
- color: navy;\r
-}\r
-dd > *:first-child {\r
- margin-top: 0.1em;\r
-}\r
-\r
-ul, ol {\r
- list-style-position: outside;\r
-}\r
-ol.arabic {\r
- list-style-type: decimal;\r
-}\r
-ol.loweralpha {\r
- list-style-type: lower-alpha;\r
-}\r
-ol.upperalpha {\r
- list-style-type: upper-alpha;\r
-}\r
-ol.lowerroman {\r
- list-style-type: lower-roman;\r
-}\r
-ol.upperroman {\r
- list-style-type: upper-roman;\r
-}\r
-\r
-div.compact ul, div.compact ol,\r
-div.compact p, div.compact p,\r
-div.compact div, div.compact div {\r
- margin-top: 0.1em;\r
- margin-bottom: 0.1em;\r
-}\r
-\r
-tfoot {\r
- font-weight: bold;\r
-}\r
-td > div.verse {\r
- white-space: pre;\r
-}\r
-\r
-div.hdlist {\r
- margin-top: 0.8em;\r
- margin-bottom: 0.8em;\r
-}\r
-div.hdlist tr {\r
- padding-bottom: 15px;\r
-}\r
-dt.hdlist1.strong, td.hdlist1.strong {\r
- font-weight: bold;\r
-}\r
-td.hdlist1 {\r
- vertical-align: top;\r
- font-style: normal;\r
- padding-right: 0.8em;\r
- color: navy;\r
-}\r
-td.hdlist2 {\r
- vertical-align: top;\r
-}\r
-div.hdlist.compact tr {\r
- margin: 0;\r
- padding-bottom: 0;\r
-}\r
-\r
-.comment {\r
- background: yellow;\r
-}\r
-\r
-.footnote, .footnoteref {\r
- font-size: 0.8em;\r
-}\r
-\r
-span.footnote, span.footnoteref {\r
- vertical-align: super;\r
-}\r
-\r
-#footnotes {\r
- margin: 20px 0 20px 0;\r
- padding: 7px 0 0 0;\r
-}\r
-\r
-#footnotes div.footnote {\r
- margin: 0 0 5px 0;\r
-}\r
-\r
-#footnotes hr {\r
- border: none;\r
- border-top: 1px solid silver;\r
- height: 1px;\r
- text-align: left;\r
- margin-left: 0;\r
- width: 20%;\r
- min-width: 100px;\r
-}\r
-\r
-div.colist td {\r
- padding-right: 0.5em;\r
- padding-bottom: 0.3em;\r
- vertical-align: top;\r
-}\r
-div.colist td img {\r
- margin-top: 0.3em;\r
-}\r
-\r
-@media print {\r
- #footer-badges { display: none; }\r
-}\r
-\r
-#toc {\r
- margin-bottom: 2.5em;\r
-}\r
-\r
-#toctitle {\r
- color: #527bbd;\r
- font-size: 1.1em;\r
- font-weight: bold;\r
- margin-top: 1.0em;\r
- margin-bottom: 0.1em;\r
-}\r
-\r
-div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {\r
- margin-top: 0;\r
- margin-bottom: 0;\r
-}\r
-div.toclevel2 {\r
- margin-left: 2em;\r
- font-size: 0.9em;\r
-}\r
-div.toclevel3 {\r
- margin-left: 4em;\r
- font-size: 0.9em;\r
-}\r
-div.toclevel4 {\r
- margin-left: 6em;\r
- font-size: 0.9em;\r
-}\r
-\r
-span.aqua { color: aqua; }\r
-span.black { color: black; }\r
-span.blue { color: blue; }\r
-span.fuchsia { color: fuchsia; }\r
-span.gray { color: gray; }\r
-span.green { color: green; }\r
-span.lime { color: lime; }\r
-span.maroon { color: maroon; }\r
-span.navy { color: navy; }\r
-span.olive { color: olive; }\r
-span.purple { color: purple; }\r
-span.red { color: red; }\r
-span.silver { color: silver; }\r
-span.teal { color: teal; }\r
-span.white { color: white; }\r
-span.yellow { color: yellow; }\r
-\r
-span.aqua-background { background: aqua; }\r
-span.black-background { background: black; }\r
-span.blue-background { background: blue; }\r
-span.fuchsia-background { background: fuchsia; }\r
-span.gray-background { background: gray; }\r
-span.green-background { background: green; }\r
-span.lime-background { background: lime; }\r
-span.maroon-background { background: maroon; }\r
-span.navy-background { background: navy; }\r
-span.olive-background { background: olive; }\r
-span.purple-background { background: purple; }\r
-span.red-background { background: red; }\r
-span.silver-background { background: silver; }\r
-span.teal-background { background: teal; }\r
-span.white-background { background: white; }\r
-span.yellow-background { background: yellow; }\r
-\r
-span.big { font-size: 2em; }\r
-span.small { font-size: 0.6em; }\r
-\r
-span.underline { text-decoration: underline; }\r
-span.overline { text-decoration: overline; }\r
-span.line-through { text-decoration: line-through; }\r
-\r
-div.unbreakable { page-break-inside: avoid; }\r
-\r
-\r
-/*\r
- * xhtml11 specific\r
- *\r
- * */\r
-\r
-div.tableblock {\r
- margin-top: 1.0em;\r
- margin-bottom: 1.5em;\r
-}\r
-div.tableblock > table {\r
- border: 3px solid #527bbd;\r
-}\r
-thead, p.table.header {\r
- font-weight: bold;\r
- color: #527bbd;\r
-}\r
-p.table {\r
- margin-top: 0;\r
-}\r
-/* Because the table frame attribute is overriden by CSS in most browsers. */\r
-div.tableblock > table[frame="void"] {\r
- border-style: none;\r
-}\r
-div.tableblock > table[frame="hsides"] {\r
- border-left-style: none;\r
- border-right-style: none;\r
-}\r
-div.tableblock > table[frame="vsides"] {\r
- border-top-style: none;\r
- border-bottom-style: none;\r
-}\r
-\r
-\r
-/*\r
- * html5 specific\r
- *\r
- * */\r
-\r
-table.tableblock {\r
- margin-top: 1.0em;\r
- margin-bottom: 1.5em;\r
-}\r
-thead, p.tableblock.header {\r
- font-weight: bold;\r
- color: #527bbd;\r
-}\r
-p.tableblock {\r
- margin-top: 0;\r
-}\r
-table.tableblock {\r
- border-width: 3px;\r
- border-spacing: 0px;\r
- border-style: solid;\r
- border-color: #527bbd;\r
- border-collapse: collapse;\r
-}\r
-th.tableblock, td.tableblock {\r
- border-width: 1px;\r
- padding: 4px;\r
- border-style: solid;\r
- border-color: #527bbd;\r
-}\r
-\r
-table.tableblock.frame-topbot {\r
- border-left-style: hidden;\r
- border-right-style: hidden;\r
-}\r
-table.tableblock.frame-sides {\r
- border-top-style: hidden;\r
- border-bottom-style: hidden;\r
-}\r
-table.tableblock.frame-none {\r
- border-style: hidden;\r
-}\r
-\r
-th.tableblock.halign-left, td.tableblock.halign-left {\r
- text-align: left;\r
-}\r
-th.tableblock.halign-center, td.tableblock.halign-center {\r
- text-align: center;\r
-}\r
-th.tableblock.halign-right, td.tableblock.halign-right {\r
- text-align: right;\r
-}\r
-\r
-th.tableblock.valign-top, td.tableblock.valign-top {\r
- vertical-align: top;\r
-}\r
-th.tableblock.valign-middle, td.tableblock.valign-middle {\r
- vertical-align: middle;\r
-}\r
-th.tableblock.valign-bottom, td.tableblock.valign-bottom {\r
- vertical-align: bottom;\r
-}\r
-\r
-\r
-/*\r
- * manpage specific\r
- *\r
- * */\r
-\r
-body.manpage h1 {\r
- padding-top: 0.5em;\r
- padding-bottom: 0.5em;\r
- border-top: 2px solid silver;\r
- border-bottom: 2px solid silver;\r
-}\r
-body.manpage h2 {\r
- border-style: none;\r
-}\r
-body.manpage div.sectionbody {\r
- margin-left: 3em;\r
-}\r
-\r
-@media print {\r
- body.manpage div#toc { display: none; }\r
-}\r
-\r
-\r
-</style>\r
-<script type="text/javascript">\r
-/*<![CDATA[*/\r
-var asciidoc = { // Namespace.\r
-\r
-/////////////////////////////////////////////////////////////////////\r
-// Table Of Contents generator\r
-/////////////////////////////////////////////////////////////////////\r
-\r
-/* Author: Mihai Bazon, September 2002\r
- * http://students.infoiasi.ro/~mishoo\r
- *\r
- * Table Of Content generator\r
- * Version: 0.4\r
- *\r
- * Feel free to use this script under the terms of the GNU General Public\r
- * License, as long as you do not remove or alter this notice.\r
- */\r
-\r
- /* modified by Troy D. Hanson, September 2006. License: GPL */\r
- /* modified by Stuart Rackham, 2006, 2009. License: GPL */\r
-\r
-// toclevels = 1..4.\r
-toc: function (toclevels) {\r
-\r
- function getText(el) {\r
- var text = "";\r
- for (var i = el.firstChild; i != null; i = i.nextSibling) {\r
- if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.\r
- text += i.data;\r
- else if (i.firstChild != null)\r
- text += getText(i);\r
- }\r
- return text;\r
- }\r
-\r
- function TocEntry(el, text, toclevel) {\r
- this.element = el;\r
- this.text = text;\r
- this.toclevel = toclevel;\r
- }\r
-\r
- function tocEntries(el, toclevels) {\r
- var result = new Array;\r
- var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');\r
- // Function that scans the DOM tree for header elements (the DOM2\r
- // nodeIterator API would be a better technique but not supported by all\r
- // browsers).\r
- var iterate = function (el) {\r
- for (var i = el.firstChild; i != null; i = i.nextSibling) {\r
- if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {\r
- var mo = re.exec(i.tagName);\r
- if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {\r
- result[result.length] = new TocEntry(i, getText(i), mo[1]-1);\r
- }\r
- iterate(i);\r
- }\r
- }\r
- }\r
- iterate(el);\r
- return result;\r
- }\r
-\r
- var toc = document.getElementById("toc");\r
- if (!toc) {\r
- return;\r
- }\r
-\r
- // Delete existing TOC entries in case we're reloading the TOC.\r
- var tocEntriesToRemove = [];\r
- var i;\r
- for (i = 0; i < toc.childNodes.length; i++) {\r
- var entry = toc.childNodes[i];\r
- if (entry.nodeName.toLowerCase() == 'div'\r
- && entry.getAttribute("class")\r
- && entry.getAttribute("class").match(/^toclevel/))\r
- tocEntriesToRemove.push(entry);\r
- }\r
- for (i = 0; i < tocEntriesToRemove.length; i++) {\r
- toc.removeChild(tocEntriesToRemove[i]);\r
- }\r
-\r
- // Rebuild TOC entries.\r
- var entries = tocEntries(document.getElementById("content"), toclevels);\r
- for (var i = 0; i < entries.length; ++i) {\r
- var entry = entries[i];\r
- if (entry.element.id == "")\r
- entry.element.id = "_toc_" + i;\r
- var a = document.createElement("a");\r
- a.href = "#" + entry.element.id;\r
- a.appendChild(document.createTextNode(entry.text));\r
- var div = document.createElement("div");\r
- div.appendChild(a);\r
- div.className = "toclevel" + entry.toclevel;\r
- toc.appendChild(div);\r
- }\r
- if (entries.length == 0)\r
- toc.parentNode.removeChild(toc);\r
-},\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////\r
-// Footnotes generator\r
-/////////////////////////////////////////////////////////////////////\r
-\r
-/* Based on footnote generation code from:\r
- * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html\r
- */\r
-\r
-footnotes: function () {\r
- // Delete existing footnote entries in case we're reloading the footnodes.\r
- var i;\r
- var noteholder = document.getElementById("footnotes");\r
- if (!noteholder) {\r
- return;\r
- }\r
- var entriesToRemove = [];\r
- for (i = 0; i < noteholder.childNodes.length; i++) {\r
- var entry = noteholder.childNodes[i];\r
- if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")\r
- entriesToRemove.push(entry);\r
- }\r
- for (i = 0; i < entriesToRemove.length; i++) {\r
- noteholder.removeChild(entriesToRemove[i]);\r
- }\r
-\r
- // Rebuild footnote entries.\r
- var cont = document.getElementById("content");\r
- var spans = cont.getElementsByTagName("span");\r
- var refs = {};\r
- var n = 0;\r
- for (i=0; i<spans.length; i++) {\r
- if (spans[i].className == "footnote") {\r
- n++;\r
- var note = spans[i].getAttribute("data-note");\r
- if (!note) {\r
- // Use [\s\S] in place of . so multi-line matches work.\r
- // Because JavaScript has no s (dotall) regex flag.\r
- note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];\r
- spans[i].innerHTML =\r
- "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +\r
- "' title='View footnote' class='footnote'>" + n + "</a>]";\r
- spans[i].setAttribute("data-note", note);\r
- }\r
- noteholder.innerHTML +=\r
- "<div class='footnote' id='_footnote_" + n + "'>" +\r
- "<a href='#_footnoteref_" + n + "' title='Return to text'>" +\r
- n + "</a>. " + note + "</div>";\r
- var id =spans[i].getAttribute("id");\r
- if (id != null) refs["#"+id] = n;\r
- }\r
- }\r
- if (n == 0)\r
- noteholder.parentNode.removeChild(noteholder);\r
- else {\r
- // Process footnoterefs.\r
- for (i=0; i<spans.length; i++) {\r
- if (spans[i].className == "footnoteref") {\r
- var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");\r
- href = href.match(/#.*/)[0]; // Because IE return full URL.\r
- n = refs[href];\r
- spans[i].innerHTML =\r
- "[<a href='#_footnote_" + n +\r
- "' title='View footnote' class='footnote'>" + n + "</a>]";\r
- }\r
- }\r
- }\r
-},\r
-\r
-install: function(toclevels) {\r
- var timerId;\r
-\r
- function reinstall() {\r
- asciidoc.footnotes();\r
- if (toclevels) {\r
- asciidoc.toc(toclevels);\r
- }\r
- }\r
-\r
- function reinstallAndRemoveTimer() {\r
- clearInterval(timerId);\r
- reinstall();\r
- }\r
-\r
- timerId = setInterval(reinstall, 500);\r
- if (document.addEventListener)\r
- document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);\r
- else\r
- window.onload = reinstallAndRemoveTimer;\r
-}\r
-\r
-}\r
-asciidoc.install(2);\r
-/*]]>*/\r
-</script>\r
-</head>\r
-<body class="article">\r
-<div id="header">\r
-<h1>ccache installation</h1>\r
-<span id="revnumber">version 3.2.9</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>\r
-<div id="content">\r
-<div class="sect1">\r
-<h2 id="_building_code_from_a_release_archive">Building code from a release archive</h2>\r
-<div class="sectionbody">\r
-<div class="sect2">\r
-<h3 id="_prerequisites">Prerequisites</h3>\r
-<div class="paragraph"><p>To build ccache, you need:</p></div>\r
-<div class="ulist"><ul>\r
-<li>\r
-<p>\r
-A C compiler (for instance GCC)\r
-</p>\r
-</li>\r
-</ul></div>\r
-<div class="paragraph"><p>It is also recommended that you have:</p></div>\r
-<div class="ulist"><ul>\r
-<li>\r
-<p>\r
-zlib <a href="http://www.zlib.net">http://www.zlib.net</a> (if you don’t have zlib installed, ccache will\r
- use a bundled copy)\r
-</p>\r
-</li>\r
-</ul></div>\r
-</div>\r
-<div class="sect2">\r
-<h3 id="_installation">Installation</h3>\r
-<div class="paragraph"><p>To compile and install ccache, run these commands:</p></div>\r
-<div class="literalblock">\r
-<div class="content">\r
-<pre><code>./configure\r
-make\r
-make install</code></pre>\r
-</div></div>\r
-<div class="paragraph"><p>You may set the installation directory and other parameters by options to\r
-“./configure”. To see them, run “./configure --help”.</p></div>\r
-<div class="paragraph"><p>There are two ways to use ccache. You can either prefix your compilation\r
-commands with “ccache” or you can create a symbolic link (named as your\r
-compiler) to ccache. The first method is most convenient if you just want to\r
-try out ccache or wish to use it for some specific projects. The second method\r
-is most useful for when you wish to use ccache for all your compilations.</p></div>\r
-<div class="paragraph"><p>To install for usage by the first method just copy ccache to somewhere in your\r
-path.</p></div>\r
-<div class="paragraph"><p>To install for the second method, do something like this:</p></div>\r
-<div class="literalblock">\r
-<div class="content">\r
-<pre><code>cp ccache /usr/local/bin/\r
-ln -s ccache /usr/local/bin/gcc\r
-ln -s ccache /usr/local/bin/g++\r
-ln -s ccache /usr/local/bin/cc\r
-ln -s ccache /usr/local/bin/c++</code></pre>\r
-</div></div>\r
-<div class="paragraph"><p>And so forth. This will work as long as “/usr/local/bin” comes before the\r
-path to the compiler (which is usually in “/usr/bin”). After installing you\r
-may wish to run “which gcc” to make sure that the correct link is being used.</p></div>\r
-<div class="admonitionblock">\r
-<table><tr>\r
-<td class="icon">\r
-<div class="title">Note</div>\r
-</td>\r
-<td class="content">Do not use a hard link, use a symbolic link. A hard link will cause\r
-“interesting” problems.</td>\r
-</tr></table>\r
-</div>\r
-</div>\r
-</div>\r
-</div>\r
-<div class="sect1">\r
-<h2 id="_building_code_from_the_source_code_repository">Building code from the source code repository</h2>\r
-<div class="sectionbody">\r
-<div class="paragraph"><p>In addition to the prerequisites mentioned above, you also need:</p></div>\r
-<div class="ulist"><ul>\r
-<li>\r
-<p>\r
-AsciiDoc (<a href="http://www.methods.co.nz/asciidoc/">http://www.methods.co.nz/asciidoc/</a>) to build the documentation.\r
-</p>\r
-</li>\r
-<li>\r
-<p>\r
-Autoconf (<a href="http://www.gnu.org/software/autoconf/">http://www.gnu.org/software/autoconf/</a>)\r
-</p>\r
-</li>\r
-<li>\r
-<p>\r
-gperf (<a href="http://www.gnu.org/software/gperf/">http://www.gnu.org/software/gperf/</a>)\r
-</p>\r
-</li>\r
-<li>\r
-<p>\r
-xsltproc (<a href="http://xmlsoft.org/XSLT/xsltproc2.html">http://xmlsoft.org/XSLT/xsltproc2.html</a>)\r
-</p>\r
-</li>\r
-</ul></div>\r
-<div class="paragraph"><p>To debug and run the performance test suite you’ll also need:</p></div>\r
-<div class="ulist"><ul>\r
-<li>\r
-<p>\r
-Python (<a href="http://www.python.org/">http://www.python.org/</a>)\r
-</p>\r
-</li>\r
-</ul></div>\r
-<div class="paragraph"><p>Run "./autogen.sh" and then follow the steps mentioned under "Installation"\r
-above.</p></div>\r
-</div>\r
-</div>\r
-</div>\r
-<div id="footnotes"><hr /></div>\r
-<div id="footer">\r
-<div id="footer-text">\r
-Version 3.2.9<br />\r
-Last updated\r
- 2016-09-28 21:28:19 CEST\r
-</div>\r
-</div>\r
-</body>\r
-</html>\r
--- /dev/null
+ccache installation
+===================
+
+Prerequisites
+-------------
+
+To build ccache, you need:
+
+- A C compiler (for instance GCC)
+
+It is also recommended that you have:
+
+- [zlib](http://www.zlib.net) (if you don't have zlib installed, ccache will
+ use a bundled copy)
+
+
+Installation
+------------
+
+To compile and install ccache, run these commands:
+
+ ./configure
+ make
+ make install
+
+You may set the installation directory and other parameters by options to
+`./configure`. To see them, run `./configure --help`.
+
+There are two ways to use ccache. You can either prefix your compilation
+commands with `ccache` or you can create a symbolic link (named as your
+compiler) to ccache. The first method is most convenient if you just want to
+try out ccache or wish to use it for some specific projects. The second method
+is most useful for when you wish to use ccache for all your compilations.
+
+To install for usage by the first method just copy ccache to somewhere in your
+path.
+
+To install for the second method, do something like this:
+
+ cp ccache /usr/local/bin/
+ ln -s ccache /usr/local/bin/gcc
+ ln -s ccache /usr/local/bin/g++
+ ln -s ccache /usr/local/bin/cc
+ ln -s ccache /usr/local/bin/c++
+
+And so forth. This will work as long as `/usr/local/bin` comes before the path
+to the compiler (which is usually in `/usr/bin`). After installing you may wish
+to run `which gcc` to make sure that the correct link is being used.
+
+NOTE: Do not use a hard link, use a symbolic link. A hard link will cause
+"interesting" problems.
+++ /dev/null
-ccache installation
-===================
-
-
-Building code from a release archive
-------------------------------------
-
-Prerequisites
-~~~~~~~~~~~~~
-
-To build ccache, you need:
-
-- A C compiler (for instance GCC)
-
-It is also recommended that you have:
-
-- zlib <http://www.zlib.net> (if you don't have zlib installed, ccache will
- use a bundled copy)
-
-
-Installation
-~~~~~~~~~~~~
-
-To compile and install ccache, run these commands:
-
- ./configure
- make
- make install
-
-You may set the installation directory and other parameters by options to
-``./configure''. To see them, run ``./configure --help''.
-
-There are two ways to use ccache. You can either prefix your compilation
-commands with ``ccache'' or you can create a symbolic link (named as your
-compiler) to ccache. The first method is most convenient if you just want to
-try out ccache or wish to use it for some specific projects. The second method
-is most useful for when you wish to use ccache for all your compilations.
-
-To install for usage by the first method just copy ccache to somewhere in your
-path.
-
-To install for the second method, do something like this:
-
- cp ccache /usr/local/bin/
- ln -s ccache /usr/local/bin/gcc
- ln -s ccache /usr/local/bin/g++
- ln -s ccache /usr/local/bin/cc
- ln -s ccache /usr/local/bin/c++
-
-And so forth. This will work as long as ``/usr/local/bin'' comes before the
-path to the compiler (which is usually in ``/usr/bin''). After installing you
-may wish to run ``which gcc'' to make sure that the correct link is being used.
-
-NOTE: Do not use a hard link, use a symbolic link. A hard link will cause
-``interesting'' problems.
-
-
-Building code from the source code repository
----------------------------------------------
-
-In addition to the prerequisites mentioned above, you also need:
-
-- AsciiDoc (http://www.methods.co.nz/asciidoc/) to build the documentation.
-- Autoconf (http://www.gnu.org/software/autoconf/)
-- gperf (http://www.gnu.org/software/gperf/)
-- xsltproc (http://xmlsoft.org/XSLT/xsltproc2.html)
-
-To debug and run the performance test suite you'll also need:
-
-- Python (http://www.python.org/)
-
-Run "./autogen.sh" and then follow the steps mentioned under "Installation"
-above.
<body class="article">\r
<div id="header">\r
<h1>ccache copyright and license</h1>\r
-<span id="revnumber">version 3.2.9</span>\r
+<span id="revnumber">version 3.2.7+172_g67acac4</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>
<h2 id="_copyright_and_authors">Copyright and authors</h2>\r
<div class="sectionbody">\r
<div class="paragraph"><p>ccache is a collective work with contributions from many people, listed in\r
-AUTHORS.txt and at <a href="http://ccache.samba.org/authors.html">http://ccache.samba.org/authors.html</a>. Subsequent additions\r
+AUTHORS.txt and at <a href="https://ccache.samba.org/authors.html">https://ccache.samba.org/authors.html</a>. Subsequent additions\r
by contributing authors are implicitly licensed to the public under the same\r
terms (GNU GPL version 3 or later), but the contributing authors retain\r
copyrights on their portions of the work.</p></div>\r
<div id="footnotes"><hr /></div>\r
<div id="footer">\r
<div id="footer-text">\r
-Version 3.2.9<br />\r
+Version 3.2.7+172_g67acac4<br />\r
Last updated\r
- 2016-09-28 21:28:19 CEST\r
+ 2016-07-28 15:37:17 CEST\r
</div>\r
</div>\r
</body>\r
---------------------
ccache is a collective work with contributions from many people, listed in
-AUTHORS.txt and at http://ccache.samba.org/authors.html. Subsequent additions
+AUTHORS.txt and at https://ccache.samba.org/authors.html. Subsequent additions
by contributing authors are implicitly licensed to the public under the same
terms (GNU GPL version 3 or later), but the contributing authors retain
copyrights on their portions of the work.
<body class="article">\r
<div id="header">\r
<h1>CCACHE(1)</h1>\r
-<span id="revnumber">version 3.2.9</span>\r
+<span id="revnumber">version 3.3</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 class="paragraph"><p>ccache has been carefully written to always produce exactly the same compiler\r
output that you would get without the cache. The only way you should be able to\r
tell that you are using ccache is the speed. Currently known exceptions to this\r
-goal are listed under <a href="#_bugs">BUGS</a>. If you ever discover an undocumented case\r
-where ccache changes the output of your compiler, please let us know.</p></div>\r
+goal are listed under <a href="#_caveats">CAVEATS</a>. If you ever discover an\r
+undocumented case where ccache changes the output of your compiler, please let\r
+us know.</p></div>\r
<div class="sect2">\r
<h3 id="_features">Features</h3>\r
<div class="ulist"><ul>\r
directory. If set to the empty string (which is the default), no rewriting\r
is done. See also the discussion under\r
<a href="#_compiling_in_different_directories">COMPILING IN DIFFERENT DIRECTORIES</a>.\r
+ If using GCC or newer versions of Clang, you might want to look into the\r
+ <strong>-fdebug-prefix-map=old=new</strong> option for relocating debug info to a common\r
+ prefix (mapping prefix with old=new).\r
</p>\r
</dd>\r
<dt class="hdlist1">\r
<dd>\r
<p>\r
This setting is a list of paths to files that ccache will include in the\r
- the hash sum that idetifies the build. The list separator is semicolon on\r
+ the hash sum that identifies the build. The list separator is semicolon on\r
Windows systems and colon on other systems.\r
</p>\r
</dd>\r
</dt>\r
<dd>\r
<p>\r
- If true, ccache will include the current working directory in the hash that\r
- is used to distinguish two compilations. This prevents a problem with the\r
- storage of the current working directory in the debug info of an object\r
- file, which can lead ccache to give a cached object file that has the\r
- working directory in the debug info set incorrectly. This option is off by\r
- default as the incorrect setting of this debug info rarely causes problems.\r
- If you strike problems with GDB not using the correct directory then enable\r
- this option.\r
+ If true (which is the default), ccache will include the current working\r
+ directory (CWD) in the hash that is used to distinguish two compilations\r
+ when generating debug info (compiler option <strong>-g</strong> with variations).\r
+ Exception: The CWD will not be included in the hash if <strong>base_dir</strong> is set\r
+ (and matches the CWD) and the compiler option <strong>-fdebug-prefix-map</strong> is used.\r
+</p>\r
+<div class="literalblock">\r
+<div class="content">\r
+<pre><code>The reason for including the CWD in the hash by default is to prevent a\r
+problem with the storage of the current working directory in the debug info\r
+of an object file, which can lead ccache to return a cached object file\r
+that has the working directory in the debug info set incorrectly.</code></pre>\r
+</div></div>\r
+<div class="literalblock">\r
+<div class="content">\r
+<pre><code>You can disable this setting to get cache hits when compiling the same\r
+source code in different directories if you don't mind that CWD in the\r
+debug info might be incorrect.</code></pre>\r
+</div></div>\r
+</dd>\r
+<dt class="hdlist1">\r
+<strong>ignore_headers_in_manifest</strong> (<strong>CCACHE_IGNOREHEADERS</strong>)\r
+</dt>\r
+<dd>\r
+<p>\r
+ This setting is a list of paths to files (or directories with headers) that\r
+ ccache will <strong>not</strong> include in the manifest list that makes up the direct\r
+ mode. Note that this can cause stale cache hits if those headers do indeed\r
+ change. The list separator is semicolon on Windows systems and colon on\r
+ other systems.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+<strong>keep_comments_cpp</strong> (<strong>CCACHE_COMMENTS</strong> or <strong>CCACHE_NOCOMMENTS</strong>, see <a href="#_boolean_values">Boolean values</a> above)\r
+</dt>\r
+<dd>\r
+<p>\r
+ If true, ccache will not discard the comments before hashing preprocessor\r
+ output. This can be used to check documentation with <strong>-Wdocumentation</strong>.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+<strong>limit_multiple</strong> (<strong>CCACHE_LIMIT_MULTIPLE</strong>)\r
+</dt>\r
+<dd>\r
+<p>\r
+ Sets the limit when cleaning up. Files are deleted (in LRU order) until the\r
+ levels are below the limit. The default is 0.8 (= 80%).\r
</p>\r
</dd>\r
<dt class="hdlist1">\r
</p>\r
</dd>\r
<dt class="hdlist1">\r
+<strong>prefix_command_cpp</strong> (<strong>CCACHE_PREFIX_CPP</strong>)\r
+</dt>\r
+<dd>\r
+<p>\r
+ This option adds a list of prefixes (separated by space) to the command\r
+ line that ccache uses when invoking the preprocessor.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
<strong>read_only</strong> (<strong>CCACHE_READONLY</strong> or <strong>CCACHE_NOREADONLY</strong>, see <a href="#_boolean_values">Boolean values</a> above)\r
</dt>\r
<dd>\r
</dt>\r
<dd>\r
<p>\r
- If true, ccache will not use the optimisation of avoiding the second call\r
- to the preprocessor by compiling the preprocessed output that was used for\r
- finding the hash in the case of a cache miss. This is primarily a debugging\r
- option, although it is possible that some unusual compilers will have\r
- problems with compiling the preprocessed output, in which case this option\r
- could allow ccache to be used anyway.\r
+ If true, ccache will first run the preprocessor to preprocess the source\r
+ code (see <a href="#_the_preprocessor_mode">THE PREPROCESSOR MODE</a>) and then on a\r
+ cache miss run the compiler on the source code to get hold of the object\r
+ file. This is the default.\r
</p>\r
+<div class="literalblock">\r
+<div class="content">\r
+<pre><code>If false, ccache will first run preprocessor to preprocess the source code\r
+and then on a cache miss run the compiler on the _preprocessed source code_\r
+instead of the original source code. This makes cache misses slightly\r
+faster since the source code only has to be preprocessed once. The downside\r
+is that some compilers won't produce the same result (for instance\r
+diagnostics warnings) when compiling preprocessed source code.</code></pre>\r
+</div></div>\r
</dd>\r
<dt class="hdlist1">\r
<strong>sloppiness</strong> (<strong>CCACHE_SLOPPINESS</strong>)\r
</p>\r
</dd>\r
<dt class="hdlist1">\r
+<strong>no_system_headers</strong>\r
+</dt>\r
+<dd>\r
+<p>\r
+ By default, ccache will also include all system headers in the manifest.\r
+ With this option set, ccache will only include system headers in the hash\r
+ but not add the system header files to the list of include files.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
<strong>pch_defines</strong>\r
</dt>\r
<dd>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
-a <strong>-Wp,<em>X</em></strong> compiler option other than <strong>-Wp,-MD,<em>path</em></strong> and\r
- <strong>-Wp,-MMD,<em>path</em></strong>\r
+a <strong>-Wp,<em>X</em></strong> compiler option other than <strong>-Wp,-MD,<em>path</em></strong>,\r
+ <strong>-Wp,-MMD,<em>path</em></strong> and <strong>-Wp,-D_define_</strong>\r
</p>\r
</li>\r
<li>\r
</li>\r
</ul></div>\r
<div class="paragraph"><p>Another minor thing is that if <strong>prefix_command</strong> is used, ccache will not invoke\r
-the other wrapper when running the preprocessor, which increase performance.</p></div>\r
+the other wrapper when running the preprocessor, which increases performance.\r
+You can use the <strong>prefix_command_cpp</strong> configuration setting if you also want to\r
+invoke the other wrapper when doing preprocessing (normally by adding <strong>-E</strong>).</p></div>\r
</div>\r
</div>\r
<div class="sect1">\r
-<h2 id="_bugs">Bugs</h2>\r
+<h2 id="_caveats">Caveats</h2>\r
<div class="sectionbody">\r
<div class="ulist"><ul>\r
<li>\r
improve performance.</p></div>\r
<div class="paragraph"><p>Since ccache works best when I/O is fast, put the cache directory on a fast\r
storage device if possible. Having lots of free memory so that files in the\r
-cache directory stay in the disk cache is also preferrable.</p></div>\r
+cache directory stay in the disk cache is also preferable.</p></div>\r
<div class="paragraph"><p>A good way of monitoring how well ccache works is to run <strong>ccache -s</strong> before and\r
after your build and then compare the statistics counters. Here are some common\r
problems and what may be done to increase the hit rate:</p></div>\r
</li>\r
<li>\r
<p>\r
-The compiler option <strong>-Xpreprocessor</strong> or <strong>-Wp,<em>X</em></strong> (except <strong>-Wp,-MD,<em>path</em></strong>\r
- and <strong>Wp,-MMD,<em>path</em></strong>) is used.\r
+The compiler option <strong>-Xpreprocessor</strong> or <strong>-Wp,<em>X</em></strong> (except <strong>-Wp,-MD,<em>path</em></strong>,\r
+ <strong>-Wp,-MMD,<em>path</em></strong>, and <strong>-Wp,-D_define_</strong>) is used.\r
</p>\r
</li>\r
<li>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_errors_when_compiling_with_ccache">Errors when compiling with ccache</h3>\r
-<div class="paragraph"><p>If compilation doesn’t work with ccache, but it works without it, one possible\r
-reason is that the compiler can’t compile preprocessed output correctly. A\r
-workaround that may work is to enable <strong>run_second_cpp</strong>*. This will make cache\r
-misses slower, though, so it is better to find and fix the root cause.</p></div>\r
-</div>\r
-<div class="sect2">\r
<h3 id="_corrupt_object_files">Corrupt object files</h3>\r
<div class="paragraph"><p>It should be noted that ccache is susceptible to general storage problems. If a\r
bad object file sneaks into the cache for some reason, it will of course stay\r
<h2 id="_more_information">More information</h2>\r
<div class="sectionbody">\r
<div class="paragraph"><p>Credits, mailing list information, bug reporting instructions, source code,\r
-etc, can be found on ccache’s web site: <a href="http://ccache.samba.org">http://ccache.samba.org</a>.</p></div>\r
+etc, can be found on ccache’s web site: <a href="https://ccache.samba.org">https://ccache.samba.org</a>.</p></div>\r
</div>\r
</div>\r
<div class="sect1">\r
<div class="sectionbody">\r
<div class="paragraph"><p>ccache was originally written by Andrew Tridgell and is currently developed and\r
maintained by Joel Rosdahl. See AUTHORS.txt or AUTHORS.html and\r
-<a href="http://ccache.samba.org/credits.html">http://ccache.samba.org/credits.html</a> for a list of contributors.</p></div>\r
+<a href="https://ccache.samba.org/credits.html">https://ccache.samba.org/credits.html</a> for a list of contributors.</p></div>\r
</div>\r
</div>\r
</div>\r
<div id="footnotes"><hr /></div>\r
<div id="footer">\r
<div id="footer-text">\r
-Version 3.2.9<br />\r
+Version 3.3<br />\r
Last updated\r
- 2016-09-28 21:28:19 CEST\r
+ 2016-08-27 16:48:16 CEST\r
</div>\r
</div>\r
</body>\r
ccache has been carefully written to always produce exactly the same compiler
output that you would get without the cache. The only way you should be able to
tell that you are using ccache is the speed. Currently known exceptions to this
-goal are listed under <<_bugs,BUGS>>. If you ever discover an undocumented case
-where ccache changes the output of your compiler, please let us know.
+goal are listed under <<_caveats,CAVEATS>>. If you ever discover an
+undocumented case where ccache changes the output of your compiler, please let
+us know.
Features
directory. If set to the empty string (which is the default), no rewriting
is done. See also the discussion under
<<_compiling_in_different_directories,COMPILING IN DIFFERENT DIRECTORIES>>.
+ If using GCC or newer versions of Clang, you might want to look into the
+ *-fdebug-prefix-map=old=new* option for relocating debug info to a common
+ prefix (mapping prefix with old=new).
*cache_dir* (*CCACHE_DIR*)::
*extra_files_to_hash* (*CCACHE_EXTRAFILES*)::
This setting is a list of paths to files that ccache will include in the
- the hash sum that idetifies the build. The list separator is semicolon on
+ the hash sum that identifies the build. The list separator is semicolon on
Windows systems and colon on other systems.
*hard_link* (*CCACHE_HARDLINK* or *CCACHE_NOHARDLINK*, see <<_boolean_values,Boolean values>> above)::
*hash_dir* (*CCACHE_HASHDIR* or *CCACHE_NOHASHDIR*, see <<_boolean_values,Boolean values>> above)::
- If true, ccache will include the current working directory in the hash that
- is used to distinguish two compilations. This prevents a problem with the
- storage of the current working directory in the debug info of an object
- file, which can lead ccache to give a cached object file that has the
- working directory in the debug info set incorrectly. This option is off by
- default as the incorrect setting of this debug info rarely causes problems.
- If you strike problems with GDB not using the correct directory then enable
- this option.
+ If true (which is the default), ccache will include the current working
+ directory (CWD) in the hash that is used to distinguish two compilations
+ when generating debug info (compiler option *-g* with variations).
+ Exception: The CWD will not be included in the hash if *base_dir* is set
+ (and matches the CWD) and the compiler option *-fdebug-prefix-map* is used.
+
+ The reason for including the CWD in the hash by default is to prevent a
+ problem with the storage of the current working directory in the debug info
+ of an object file, which can lead ccache to return a cached object file
+ that has the working directory in the debug info set incorrectly.
+
+ You can disable this setting to get cache hits when compiling the same
+ source code in different directories if you don't mind that CWD in the
+ debug info might be incorrect.
+
+*ignore_headers_in_manifest* (*CCACHE_IGNOREHEADERS*)::
+
+ This setting is a list of paths to files (or directories with headers) that
+ ccache will *not* include in the manifest list that makes up the direct
+ mode. Note that this can cause stale cache hits if those headers do indeed
+ change. The list separator is semicolon on Windows systems and colon on
+ other systems.
+
+*keep_comments_cpp* (*CCACHE_COMMENTS* or *CCACHE_NOCOMMENTS*, see <<_boolean_values,Boolean values>> above)::
+
+ If true, ccache will not discard the comments before hashing preprocessor
+ output. This can be used to check documentation with *-Wdocumentation*.
+
+*limit_multiple* (*CCACHE_LIMIT_MULTIPLE*)::
+
+ Sets the limit when cleaning up. Files are deleted (in LRU order) until the
+ levels are below the limit. The default is 0.8 (= 80%).
*log_file* (*CCACHE_LOGFILE*)::
<<_using_ccache_with_other_compiler_wrappers,USING CCACHE WITH OTHER
COMPILER WRAPPERS>>.
+*prefix_command_cpp* (*CCACHE_PREFIX_CPP*)::
+
+ This option adds a list of prefixes (separated by space) to the command
+ line that ccache uses when invoking the preprocessor.
+
*read_only* (*CCACHE_READONLY* or *CCACHE_NOREADONLY*, see <<_boolean_values,Boolean values>> above)::
If true, ccache will attempt to use existing cached object files, but it
*run_second_cpp* (*CCACHE_CPP2* or *CCACHE_NOCPP2*, see <<_boolean_values,Boolean values>> above)::
- If true, ccache will not use the optimisation of avoiding the second call
- to the preprocessor by compiling the preprocessed output that was used for
- finding the hash in the case of a cache miss. This is primarily a debugging
- option, although it is possible that some unusual compilers will have
- problems with compiling the preprocessed output, in which case this option
- could allow ccache to be used anyway.
+ If true, ccache will first run the preprocessor to preprocess the source
+ code (see <<_the_preprocessor_mode,THE PREPROCESSOR MODE>>) and then on a
+ cache miss run the compiler on the source code to get hold of the object
+ file. This is the default.
+
+ If false, ccache will first run preprocessor to preprocess the source code
+ and then on a cache miss run the compiler on the _preprocessed source code_
+ instead of the original source code. This makes cache misses slightly
+ faster since the source code only has to be preprocessed once. The downside
+ is that some compilers won't produce the same result (for instance
+ diagnostics warnings) when compiling preprocessed source code.
*sloppiness* (*CCACHE_SLOPPINESS*)::
*include_file_mtime*::
By default, ccache will not cache a file if it includes a header whose
mtime is too new. This option disables that check.
+*no_system_headers*::
+ By default, ccache will also include all system headers in the manifest.
+ With this option set, ccache will only include system headers in the hash
+ but not add the system header files to the list of include files.
*pch_defines*::
Be sloppy about #defines when precompiling a header file. See
<<_precompiled_headers,PRECOMPILED HEADERS>> for more information.
race condition)
* the unifier is enabled (the configuration setting *unify* is true)
* a compiler option not supported by the direct mode is used:
-** a *-Wp,_X_* compiler option other than *-Wp,-MD,_path_* and
- *-Wp,-MMD,_path_*
+** a *-Wp,_X_* compiler option other than *-Wp,-MD,_path_*,
+ *-Wp,-MMD,_path_* and *-Wp,-D_define_*
** *-Xpreprocessor*
* the string ``\_\_TIME__'' is present in the source code
the other wrapper.
Another minor thing is that if *prefix_command* is used, ccache will not invoke
-the other wrapper when running the preprocessor, which increase performance.
+the other wrapper when running the preprocessor, which increases performance.
+You can use the *prefix_command_cpp* configuration setting if you also want to
+invoke the other wrapper when doing preprocessing (normally by adding *-E*).
-Bugs
-----
+Caveats
+-------
* ccache doesn't handle the GNU Assembler's *.incbin* directive correctly. This
directive can be embedded in the source code inside an *__asm__* statement in
Since ccache works best when I/O is fast, put the cache directory on a fast
storage device if possible. Having lots of free memory so that files in the
-cache directory stay in the disk cache is also preferrable.
+cache directory stay in the disk cache is also preferable.
A good way of monitoring how well ccache works is to run *ccache -s* before and
after your build and then compare the statistics counters. Here are some common
** Compiler arguments that are hashed in the direct mode but not in the
preprocessor mode have changed (*-I*, *-include*, *-D*, etc) and they didn't
affect the preprocessor output.
-** The compiler option *-Xpreprocessor* or *-Wp,_X_* (except *-Wp,-MD,_path_*
- and *Wp,-MMD,_path_*) is used.
+** The compiler option *-Xpreprocessor* or *-Wp,_X_* (except *-Wp,-MD,_path_*,
+ *-Wp,-MMD,_path_*, and *-Wp,-D_define_*) is used.
** This was the first compilation with a new value of the base directory
setting.
** A modification time of one of the include files is too new (created the same
<<_precompiled_headers,PRECOMPILED HEADERS>>.
-Errors when compiling with ccache
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If compilation doesn't work with ccache, but it works without it, one possible
-reason is that the compiler can't compile preprocessed output correctly. A
-workaround that may work is to enable *run_second_cpp**. This will make cache
-misses slower, though, so it is better to find and fix the root cause.
-
-
Corrupt object files
~~~~~~~~~~~~~~~~~~~~
----------------
Credits, mailing list information, bug reporting instructions, source code,
-etc, can be found on ccache's web site: <http://ccache.samba.org>.
+etc, can be found on ccache's web site: <https://ccache.samba.org>.
Author
ccache was originally written by Andrew Tridgell and is currently developed and
maintained by Joel Rosdahl. See AUTHORS.txt or AUTHORS.html and
-<http://ccache.samba.org/credits.html> for a list of contributors.
+<https://ccache.samba.org/credits.html> for a list of contributors.
all_sources = $(ccache_sources) $(test_sources)
all_objs = $(ccache_objs) $(test_objs) $(zlib_objs)
-files_to_clean = $(all_objs) ccache$(EXEEXT) test/main$(EXEEXT) *~
+files_to_clean = $(all_objs) ccache$(EXEEXT) test/main$(EXEEXT) *~ testdir.*
files_to_distclean = Makefile config.h config.log config.status
.PHONY: all
.PHONY: clean
clean:
- rm -f $(files_to_clean)
+ rm -rf $(files_to_clean)
conf.c: confitems_lookup.c envtoconfitems_lookup.c
<body class="article">\r
<div id="header">\r
<h1>ccache news</h1>\r
-<span id="revnumber">version 3.2.9</span>\r
+<span id="revnumber">version 3.3</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>\r
<div id="content">\r
-<div id="preamble">\r
+<div class="sect1">\r
+<h2 id="_ccache_3_3">ccache 3.3</h2>\r
<div class="sectionbody">\r
-<div class="paragraph"><p>ccache 3.2.9</p></div>\r
-<div class="listingblock">\r
-<div class="content">\r
-<pre><code>Release date: 2016-09-28\r
-\r
-Bug fixes\r
-~~~~~~~~~\r
-\r
-- Fixed a regression in ccache 3.2.8: ccache could get confused when using the\r
- compiler option `-Wp,` to pass multiple options to the preprocessor,\r
- resulting in missing dependency files from direct mode cache hits.\r
-\r
-\r
-ccache 3.2.8</code></pre>\r
-</div></div>\r
-<div class="paragraph"><p>Release date: 2016-09-07</p></div>\r
-</div>\r
+<div class="paragraph"><p>Release date: 2016-08-27</p></div>\r
+<div class="sect2">\r
+<h3 id="_notes">Notes</h3>\r
+<div class="ulist"><ul>\r
+<li>\r
+<p>\r
+A C99-compatible compiler is now required to build ccache.\r
+</p>\r
+</li>\r
+</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_bug_fixes">Bug fixes</h3>\r
+<h3 id="_new_features_and_improvements">New features and improvements</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
-Fixed an issue when compiler option <code>-Wp,-MT,path</code> is used instead of <code>-MT\r
- path</code> (and similar for <code>-MF</code>, <code>-MP</code> and <code>-MQ</code>) and <code>run_second_cpp</code>\r
- (<code>CCACHE_CPP2</code>) is enabled.\r
+The configuration option <code>run_second_cpp</code> (<code>CCACHE_CPP2</code>) now defaults to\r
+ true. This improves ccache’s out-of-the-box experience for compilers that\r
+ can’t compile their own preprocessed output with the same outcome as if they\r
+ compiled the real source code directly, e.g. newer versions of GCC and Clang.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+The configuration option <code>hash_dir</code> (<code>CCACHE_HASHDIR</code>) now defaults to true.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added a new <code>ignore_headers_in_manifest</code> configuration option, which\r
+ specifies headers that should be ignored in the direct mode.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added a new <code>prefix_command_cpp</code> (<code>CCACHE_PREFIX_CPP</code>) configuration option,\r
+ which specifies one or several prefixes to add to the command line ccache\r
+ uses when invoking the preprocessor.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added a new <code>limit_multiple</code> (<code>CCACHE_LIMIT_MULTIPLE</code>) configuration option,\r
+ which specifies how much of the cache to remove when cleaning.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added a new <code>keep_comments_cpp</code> (<code>CCACHE_COMMENTS</code>) configuration option,\r
+ which tells ccache not to discard the comments before hashing preprocessor\r
+ output. This can be used to check documentation with <strong>-Wdocumentation</strong>.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added a new sloppiness option <code>no_system_headers</code>, which tells ccache not to\r
+ include system headers in manifest files.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added a new statistics counter that tracks the number of performed cleanups\r
+ due to the cache size being over the limit. The value is shown in the output\r
+ of “ccache -s”.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added support for relocating debug info directory using <code>-fdebug-prefix-map</code>.\r
+ This allows for cache hits even when <code>hash_dir</code> is used in combination with\r
+ <code>base_dir</code>.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added a new “cache hit rate” field to the output of “ccache -s”.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added support for caching compilation of assembler code produced by e.g.\r
+ “gcc -S file.c”.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added support for cuda including the -optf/--options-file option.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added support for Fortran 77.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added support for multiple <code>-arch</code> options to produce "fat binaries".\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Multiple identical <code>-arch</code> arguments are now handled without bailing.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+The concatenated form of some long compiler options is now recognized, for\r
+ example when using <code>-isystemPATH</code> instead of <code>-isystem PATH</code>.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+If hard-linking is enabled and but fails (e.g. due to cross-device linking),\r
+ ccache now falls back to copying instead of running the compiler.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Made the <code>hash_dir</code> option only have effect when generating debug info.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+ccache now knows how to convert absolute paths to relative paths inside\r
+ dependency files when using <code>base_dir</code>.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Improved parsing of <code>-g*</code> options.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Made ccache understand <code>-Wp,-D*</code> options.\r
</p>\r
</li>\r
<li>\r
option.\r
</p>\r
</li>\r
+<li>\r
+<p>\r
+Names of included files are no longer included in the hash of the compiler’s\r
+ preprocessed output. This leads to more potential cache hits when not using\r
+ the direct mode.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Increased buffer size used when reading file data. This improves performance\r
+ slightly.\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
+Bail out on too hard compiler option <code>-P</code>.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Fixed clang test suite when running on Linux.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Fixed build and test for MinGW32 and Windows.\r
+</p>\r
+</li>\r
</ul></div>\r
</div>\r
+</div>\r
+</div>\r
<div class="sect1">\r
<h2 id="_ccache_3_2_7">ccache 3.2.7</h2>\r
<div class="sectionbody">\r
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2016-04-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
<div class="sectionbody">\r
<div class="paragraph"><p>Release date: 2015-08-16</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
<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_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
<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_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
<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_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
<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_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
<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_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
<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_8">New features and improvements</h3>\r
+<h3 id="_new_features_and_improvements_9">New features and improvements</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
<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_9">New features and improvements</h3>\r
+<h3 id="_new_features_and_improvements_10">New features and improvements</h3>\r
<div class="ulist"><ul>\r
<li>\r
<p>\r
</ul></div>\r
</div>\r
<div class="sect2">\r
-<h3 id="_new_features_and_improvements_10">New features and improvements</h3>\r
+<h3 id="_new_features_and_improvements_11">New features and improvements</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.2.9<br />\r
+Version 3.3<br />\r
Last updated\r
- 2016-09-28 22:19:01 CEST\r
+ 2016-08-27 16:52:44 CEST\r
</div>\r
</div>\r
</body>\r
ccache news
===========
-ccache 3.2.9
-----------------
-Release date: 2016-09-28
-Bug fixes
-~~~~~~~~~
+ccache 3.3
+----------
+Release date: 2016-08-27
-- Fixed a regression in ccache 3.2.8: ccache could get confused when using the
- compiler option `-Wp,` to pass multiple options to the preprocessor,
- resulting in missing dependency files from direct mode cache hits.
+Notes
+~~~~~
+- A C99-compatible compiler is now required to build ccache.
-ccache 3.2.8
-------------
-Release date: 2016-09-07
-Bug fixes
-~~~~~~~~~
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- The configuration option `run_second_cpp` (`CCACHE_CPP2`) now defaults to
+ true. This improves ccache's out-of-the-box experience for compilers that
+ can't compile their own preprocessed output with the same outcome as if they
+ compiled the real source code directly, e.g. newer versions of GCC and Clang.
+
+- The configuration option `hash_dir` (`CCACHE_HASHDIR`) now defaults to true.
+
+- Added a new `ignore_headers_in_manifest` configuration option, which
+ specifies headers that should be ignored in the direct mode.
+
+- Added a new `prefix_command_cpp` (`CCACHE_PREFIX_CPP`) configuration option,
+ which specifies one or several prefixes to add to the command line ccache
+ uses when invoking the preprocessor.
+
+- Added a new `limit_multiple` (`CCACHE_LIMIT_MULTIPLE`) configuration option,
+ which specifies how much of the cache to remove when cleaning.
+
+- Added a new `keep_comments_cpp` (`CCACHE_COMMENTS`) configuration option,
+ which tells ccache not to discard the comments before hashing preprocessor
+ output. This can be used to check documentation with *-Wdocumentation*.
+
+- Added a new sloppiness option `no_system_headers`, which tells ccache not to
+ include system headers in manifest files.
+
+- Added a new statistics counter that tracks the number of performed cleanups
+ due to the cache size being over the limit. The value is shown in the output
+ of ``ccache -s''.
+
+- Added support for relocating debug info directory using `-fdebug-prefix-map`.
+ This allows for cache hits even when `hash_dir` is used in combination with
+ `base_dir`.
+
+- Added a new ``cache hit rate'' field to the output of ``ccache -s''.
+
+- Added support for caching compilation of assembler code produced by e.g.
+ ``gcc -S file.c''.
-- Fixed an issue when compiler option `-Wp,-MT,path` is used instead of `-MT
- path` (and similar for `-MF`, `-MP` and `-MQ`) and `run_second_cpp`
- (`CCACHE_CPP2`) is enabled.
+- Added support for cuda including the -optf/--options-file option.
+
+- Added support for Fortran 77.
+
+- Added support for multiple `-arch` options to produce "fat binaries".
+
+- Multiple identical `-arch` arguments are now handled without bailing.
+
+- The concatenated form of some long compiler options is now recognized, for
+ example when using `-isystemPATH` instead of `-isystem PATH`.
+
+- If hard-linking is enabled and but fails (e.g. due to cross-device linking),
+ ccache now falls back to copying instead of running the compiler.
+
+- Made the `hash_dir` option only have effect when generating debug info.
+
+- ccache now knows how to convert absolute paths to relative paths inside
+ dependency files when using `base_dir`.
+
+- Improved parsing of `-g*` options.
+
+- Made ccache understand `-Wp,-D*` options.
- ccache now understands the undocumented `-coverage` (only one dash) GCC
option.
+- Names of included files are no longer included in the hash of the compiler's
+ preprocessed output. This leads to more potential cache hits when not using
+ the direct mode.
+
+- Increased buffer size used when reading file data. This improves performance
+ slightly.
+
+
+Bug fixes
+~~~~~~~~~
+
+- Bail out on too hard compiler option `-P`.
+
+- Fixed clang test suite when running on Linux.
+
+- Fixed build and test for MinGW32 and Windows.
+
ccache 3.2.7
------------
------------
Release date: 2016-04-17
+
New features and improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+++ /dev/null
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"\r
- "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\r
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">\r
-<head>\r
-<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />\r
-<meta name="generator" content="AsciiDoc 8.6.9" />\r
-<title>ccache README</title>\r
-<style type="text/css">\r
-/* Shared CSS for AsciiDoc xhtml11 and html5 backends */\r
-\r
-/* Default font. */\r
-body {\r
- font-family: Georgia,serif;\r
-}\r
-\r
-/* Title font. */\r
-h1, h2, h3, h4, h5, h6,\r
-div.title, caption.title,\r
-thead, p.table.header,\r
-#toctitle,\r
-#author, #revnumber, #revdate, #revremark,\r
-#footer {\r
- font-family: Arial,Helvetica,sans-serif;\r
-}\r
-\r
-body {\r
- margin: 1em 5% 1em 5%;\r
-}\r
-\r
-a {\r
- color: blue;\r
- text-decoration: underline;\r
-}\r
-a:visited {\r
- color: fuchsia;\r
-}\r
-\r
-em {\r
- font-style: italic;\r
- color: navy;\r
-}\r
-\r
-strong {\r
- font-weight: bold;\r
- color: #083194;\r
-}\r
-\r
-h1, h2, h3, h4, h5, h6 {\r
- color: #527bbd;\r
- margin-top: 1.2em;\r
- margin-bottom: 0.5em;\r
- line-height: 1.3;\r
-}\r
-\r
-h1, h2, h3 {\r
- border-bottom: 2px solid silver;\r
-}\r
-h2 {\r
- padding-top: 0.5em;\r
-}\r
-h3 {\r
- float: left;\r
-}\r
-h3 + * {\r
- clear: left;\r
-}\r
-h5 {\r
- font-size: 1.0em;\r
-}\r
-\r
-div.sectionbody {\r
- margin-left: 0;\r
-}\r
-\r
-hr {\r
- border: 1px solid silver;\r
-}\r
-\r
-p {\r
- margin-top: 0.5em;\r
- margin-bottom: 0.5em;\r
-}\r
-\r
-ul, ol, li > p {\r
- margin-top: 0;\r
-}\r
-ul > li { color: #aaa; }\r
-ul > li > * { color: black; }\r
-\r
-.monospaced, code, pre {\r
- font-family: "Courier New", Courier, monospace;\r
- font-size: inherit;\r
- color: navy;\r
- padding: 0;\r
- margin: 0;\r
-}\r
-pre {\r
- white-space: pre-wrap;\r
-}\r
-\r
-#author {\r
- color: #527bbd;\r
- font-weight: bold;\r
- font-size: 1.1em;\r
-}\r
-#email {\r
-}\r
-#revnumber, #revdate, #revremark {\r
-}\r
-\r
-#footer {\r
- font-size: small;\r
- border-top: 2px solid silver;\r
- padding-top: 0.5em;\r
- margin-top: 4.0em;\r
-}\r
-#footer-text {\r
- float: left;\r
- padding-bottom: 0.5em;\r
-}\r
-#footer-badges {\r
- float: right;\r
- padding-bottom: 0.5em;\r
-}\r
-\r
-#preamble {\r
- margin-top: 1.5em;\r
- margin-bottom: 1.5em;\r
-}\r
-div.imageblock, div.exampleblock, div.verseblock,\r
-div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,\r
-div.admonitionblock {\r
- margin-top: 1.0em;\r
- margin-bottom: 1.5em;\r
-}\r
-div.admonitionblock {\r
- margin-top: 2.0em;\r
- margin-bottom: 2.0em;\r
- margin-right: 10%;\r
- color: #606060;\r
-}\r
-\r
-div.content { /* Block element content. */\r
- padding: 0;\r
-}\r
-\r
-/* Block element titles. */\r
-div.title, caption.title {\r
- color: #527bbd;\r
- font-weight: bold;\r
- text-align: left;\r
- margin-top: 1.0em;\r
- margin-bottom: 0.5em;\r
-}\r
-div.title + * {\r
- margin-top: 0;\r
-}\r
-\r
-td div.title:first-child {\r
- margin-top: 0.0em;\r
-}\r
-div.content div.title:first-child {\r
- margin-top: 0.0em;\r
-}\r
-div.content + div.title {\r
- margin-top: 0.0em;\r
-}\r
-\r
-div.sidebarblock > div.content {\r
- background: #ffffee;\r
- border: 1px solid #dddddd;\r
- border-left: 4px solid #f0f0f0;\r
- padding: 0.5em;\r
-}\r
-\r
-div.listingblock > div.content {\r
- border: 1px solid #dddddd;\r
- border-left: 5px solid #f0f0f0;\r
- background: #f8f8f8;\r
- padding: 0.5em;\r
-}\r
-\r
-div.quoteblock, div.verseblock {\r
- padding-left: 1.0em;\r
- margin-left: 1.0em;\r
- margin-right: 10%;\r
- border-left: 5px solid #f0f0f0;\r
- color: #888;\r
-}\r
-\r
-div.quoteblock > div.attribution {\r
- padding-top: 0.5em;\r
- text-align: right;\r
-}\r
-\r
-div.verseblock > pre.content {\r
- font-family: inherit;\r
- font-size: inherit;\r
-}\r
-div.verseblock > div.attribution {\r
- padding-top: 0.75em;\r
- text-align: left;\r
-}\r
-/* DEPRECATED: Pre version 8.2.7 verse style literal block. */\r
-div.verseblock + div.attribution {\r
- text-align: left;\r
-}\r
-\r
-div.admonitionblock .icon {\r
- vertical-align: top;\r
- font-size: 1.1em;\r
- font-weight: bold;\r
- text-decoration: underline;\r
- color: #527bbd;\r
- padding-right: 0.5em;\r
-}\r
-div.admonitionblock td.content {\r
- padding-left: 0.5em;\r
- border-left: 3px solid #dddddd;\r
-}\r
-\r
-div.exampleblock > div.content {\r
- border-left: 3px solid #dddddd;\r
- padding-left: 0.5em;\r
-}\r
-\r
-div.imageblock div.content { padding-left: 0; }\r
-span.image img { border-style: none; vertical-align: text-bottom; }\r
-a.image:visited { color: white; }\r
-\r
-dl {\r
- margin-top: 0.8em;\r
- margin-bottom: 0.8em;\r
-}\r
-dt {\r
- margin-top: 0.5em;\r
- margin-bottom: 0;\r
- font-style: normal;\r
- color: navy;\r
-}\r
-dd > *:first-child {\r
- margin-top: 0.1em;\r
-}\r
-\r
-ul, ol {\r
- list-style-position: outside;\r
-}\r
-ol.arabic {\r
- list-style-type: decimal;\r
-}\r
-ol.loweralpha {\r
- list-style-type: lower-alpha;\r
-}\r
-ol.upperalpha {\r
- list-style-type: upper-alpha;\r
-}\r
-ol.lowerroman {\r
- list-style-type: lower-roman;\r
-}\r
-ol.upperroman {\r
- list-style-type: upper-roman;\r
-}\r
-\r
-div.compact ul, div.compact ol,\r
-div.compact p, div.compact p,\r
-div.compact div, div.compact div {\r
- margin-top: 0.1em;\r
- margin-bottom: 0.1em;\r
-}\r
-\r
-tfoot {\r
- font-weight: bold;\r
-}\r
-td > div.verse {\r
- white-space: pre;\r
-}\r
-\r
-div.hdlist {\r
- margin-top: 0.8em;\r
- margin-bottom: 0.8em;\r
-}\r
-div.hdlist tr {\r
- padding-bottom: 15px;\r
-}\r
-dt.hdlist1.strong, td.hdlist1.strong {\r
- font-weight: bold;\r
-}\r
-td.hdlist1 {\r
- vertical-align: top;\r
- font-style: normal;\r
- padding-right: 0.8em;\r
- color: navy;\r
-}\r
-td.hdlist2 {\r
- vertical-align: top;\r
-}\r
-div.hdlist.compact tr {\r
- margin: 0;\r
- padding-bottom: 0;\r
-}\r
-\r
-.comment {\r
- background: yellow;\r
-}\r
-\r
-.footnote, .footnoteref {\r
- font-size: 0.8em;\r
-}\r
-\r
-span.footnote, span.footnoteref {\r
- vertical-align: super;\r
-}\r
-\r
-#footnotes {\r
- margin: 20px 0 20px 0;\r
- padding: 7px 0 0 0;\r
-}\r
-\r
-#footnotes div.footnote {\r
- margin: 0 0 5px 0;\r
-}\r
-\r
-#footnotes hr {\r
- border: none;\r
- border-top: 1px solid silver;\r
- height: 1px;\r
- text-align: left;\r
- margin-left: 0;\r
- width: 20%;\r
- min-width: 100px;\r
-}\r
-\r
-div.colist td {\r
- padding-right: 0.5em;\r
- padding-bottom: 0.3em;\r
- vertical-align: top;\r
-}\r
-div.colist td img {\r
- margin-top: 0.3em;\r
-}\r
-\r
-@media print {\r
- #footer-badges { display: none; }\r
-}\r
-\r
-#toc {\r
- margin-bottom: 2.5em;\r
-}\r
-\r
-#toctitle {\r
- color: #527bbd;\r
- font-size: 1.1em;\r
- font-weight: bold;\r
- margin-top: 1.0em;\r
- margin-bottom: 0.1em;\r
-}\r
-\r
-div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {\r
- margin-top: 0;\r
- margin-bottom: 0;\r
-}\r
-div.toclevel2 {\r
- margin-left: 2em;\r
- font-size: 0.9em;\r
-}\r
-div.toclevel3 {\r
- margin-left: 4em;\r
- font-size: 0.9em;\r
-}\r
-div.toclevel4 {\r
- margin-left: 6em;\r
- font-size: 0.9em;\r
-}\r
-\r
-span.aqua { color: aqua; }\r
-span.black { color: black; }\r
-span.blue { color: blue; }\r
-span.fuchsia { color: fuchsia; }\r
-span.gray { color: gray; }\r
-span.green { color: green; }\r
-span.lime { color: lime; }\r
-span.maroon { color: maroon; }\r
-span.navy { color: navy; }\r
-span.olive { color: olive; }\r
-span.purple { color: purple; }\r
-span.red { color: red; }\r
-span.silver { color: silver; }\r
-span.teal { color: teal; }\r
-span.white { color: white; }\r
-span.yellow { color: yellow; }\r
-\r
-span.aqua-background { background: aqua; }\r
-span.black-background { background: black; }\r
-span.blue-background { background: blue; }\r
-span.fuchsia-background { background: fuchsia; }\r
-span.gray-background { background: gray; }\r
-span.green-background { background: green; }\r
-span.lime-background { background: lime; }\r
-span.maroon-background { background: maroon; }\r
-span.navy-background { background: navy; }\r
-span.olive-background { background: olive; }\r
-span.purple-background { background: purple; }\r
-span.red-background { background: red; }\r
-span.silver-background { background: silver; }\r
-span.teal-background { background: teal; }\r
-span.white-background { background: white; }\r
-span.yellow-background { background: yellow; }\r
-\r
-span.big { font-size: 2em; }\r
-span.small { font-size: 0.6em; }\r
-\r
-span.underline { text-decoration: underline; }\r
-span.overline { text-decoration: overline; }\r
-span.line-through { text-decoration: line-through; }\r
-\r
-div.unbreakable { page-break-inside: avoid; }\r
-\r
-\r
-/*\r
- * xhtml11 specific\r
- *\r
- * */\r
-\r
-div.tableblock {\r
- margin-top: 1.0em;\r
- margin-bottom: 1.5em;\r
-}\r
-div.tableblock > table {\r
- border: 3px solid #527bbd;\r
-}\r
-thead, p.table.header {\r
- font-weight: bold;\r
- color: #527bbd;\r
-}\r
-p.table {\r
- margin-top: 0;\r
-}\r
-/* Because the table frame attribute is overriden by CSS in most browsers. */\r
-div.tableblock > table[frame="void"] {\r
- border-style: none;\r
-}\r
-div.tableblock > table[frame="hsides"] {\r
- border-left-style: none;\r
- border-right-style: none;\r
-}\r
-div.tableblock > table[frame="vsides"] {\r
- border-top-style: none;\r
- border-bottom-style: none;\r
-}\r
-\r
-\r
-/*\r
- * html5 specific\r
- *\r
- * */\r
-\r
-table.tableblock {\r
- margin-top: 1.0em;\r
- margin-bottom: 1.5em;\r
-}\r
-thead, p.tableblock.header {\r
- font-weight: bold;\r
- color: #527bbd;\r
-}\r
-p.tableblock {\r
- margin-top: 0;\r
-}\r
-table.tableblock {\r
- border-width: 3px;\r
- border-spacing: 0px;\r
- border-style: solid;\r
- border-color: #527bbd;\r
- border-collapse: collapse;\r
-}\r
-th.tableblock, td.tableblock {\r
- border-width: 1px;\r
- padding: 4px;\r
- border-style: solid;\r
- border-color: #527bbd;\r
-}\r
-\r
-table.tableblock.frame-topbot {\r
- border-left-style: hidden;\r
- border-right-style: hidden;\r
-}\r
-table.tableblock.frame-sides {\r
- border-top-style: hidden;\r
- border-bottom-style: hidden;\r
-}\r
-table.tableblock.frame-none {\r
- border-style: hidden;\r
-}\r
-\r
-th.tableblock.halign-left, td.tableblock.halign-left {\r
- text-align: left;\r
-}\r
-th.tableblock.halign-center, td.tableblock.halign-center {\r
- text-align: center;\r
-}\r
-th.tableblock.halign-right, td.tableblock.halign-right {\r
- text-align: right;\r
-}\r
-\r
-th.tableblock.valign-top, td.tableblock.valign-top {\r
- vertical-align: top;\r
-}\r
-th.tableblock.valign-middle, td.tableblock.valign-middle {\r
- vertical-align: middle;\r
-}\r
-th.tableblock.valign-bottom, td.tableblock.valign-bottom {\r
- vertical-align: bottom;\r
-}\r
-\r
-\r
-/*\r
- * manpage specific\r
- *\r
- * */\r
-\r
-body.manpage h1 {\r
- padding-top: 0.5em;\r
- padding-bottom: 0.5em;\r
- border-top: 2px solid silver;\r
- border-bottom: 2px solid silver;\r
-}\r
-body.manpage h2 {\r
- border-style: none;\r
-}\r
-body.manpage div.sectionbody {\r
- margin-left: 3em;\r
-}\r
-\r
-@media print {\r
- body.manpage div#toc { display: none; }\r
-}\r
-\r
-\r
-</style>\r
-<script type="text/javascript">\r
-/*<![CDATA[*/\r
-var asciidoc = { // Namespace.\r
-\r
-/////////////////////////////////////////////////////////////////////\r
-// Table Of Contents generator\r
-/////////////////////////////////////////////////////////////////////\r
-\r
-/* Author: Mihai Bazon, September 2002\r
- * http://students.infoiasi.ro/~mishoo\r
- *\r
- * Table Of Content generator\r
- * Version: 0.4\r
- *\r
- * Feel free to use this script under the terms of the GNU General Public\r
- * License, as long as you do not remove or alter this notice.\r
- */\r
-\r
- /* modified by Troy D. Hanson, September 2006. License: GPL */\r
- /* modified by Stuart Rackham, 2006, 2009. License: GPL */\r
-\r
-// toclevels = 1..4.\r
-toc: function (toclevels) {\r
-\r
- function getText(el) {\r
- var text = "";\r
- for (var i = el.firstChild; i != null; i = i.nextSibling) {\r
- if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.\r
- text += i.data;\r
- else if (i.firstChild != null)\r
- text += getText(i);\r
- }\r
- return text;\r
- }\r
-\r
- function TocEntry(el, text, toclevel) {\r
- this.element = el;\r
- this.text = text;\r
- this.toclevel = toclevel;\r
- }\r
-\r
- function tocEntries(el, toclevels) {\r
- var result = new Array;\r
- var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');\r
- // Function that scans the DOM tree for header elements (the DOM2\r
- // nodeIterator API would be a better technique but not supported by all\r
- // browsers).\r
- var iterate = function (el) {\r
- for (var i = el.firstChild; i != null; i = i.nextSibling) {\r
- if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {\r
- var mo = re.exec(i.tagName);\r
- if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {\r
- result[result.length] = new TocEntry(i, getText(i), mo[1]-1);\r
- }\r
- iterate(i);\r
- }\r
- }\r
- }\r
- iterate(el);\r
- return result;\r
- }\r
-\r
- var toc = document.getElementById("toc");\r
- if (!toc) {\r
- return;\r
- }\r
-\r
- // Delete existing TOC entries in case we're reloading the TOC.\r
- var tocEntriesToRemove = [];\r
- var i;\r
- for (i = 0; i < toc.childNodes.length; i++) {\r
- var entry = toc.childNodes[i];\r
- if (entry.nodeName.toLowerCase() == 'div'\r
- && entry.getAttribute("class")\r
- && entry.getAttribute("class").match(/^toclevel/))\r
- tocEntriesToRemove.push(entry);\r
- }\r
- for (i = 0; i < tocEntriesToRemove.length; i++) {\r
- toc.removeChild(tocEntriesToRemove[i]);\r
- }\r
-\r
- // Rebuild TOC entries.\r
- var entries = tocEntries(document.getElementById("content"), toclevels);\r
- for (var i = 0; i < entries.length; ++i) {\r
- var entry = entries[i];\r
- if (entry.element.id == "")\r
- entry.element.id = "_toc_" + i;\r
- var a = document.createElement("a");\r
- a.href = "#" + entry.element.id;\r
- a.appendChild(document.createTextNode(entry.text));\r
- var div = document.createElement("div");\r
- div.appendChild(a);\r
- div.className = "toclevel" + entry.toclevel;\r
- toc.appendChild(div);\r
- }\r
- if (entries.length == 0)\r
- toc.parentNode.removeChild(toc);\r
-},\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////\r
-// Footnotes generator\r
-/////////////////////////////////////////////////////////////////////\r
-\r
-/* Based on footnote generation code from:\r
- * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html\r
- */\r
-\r
-footnotes: function () {\r
- // Delete existing footnote entries in case we're reloading the footnodes.\r
- var i;\r
- var noteholder = document.getElementById("footnotes");\r
- if (!noteholder) {\r
- return;\r
- }\r
- var entriesToRemove = [];\r
- for (i = 0; i < noteholder.childNodes.length; i++) {\r
- var entry = noteholder.childNodes[i];\r
- if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")\r
- entriesToRemove.push(entry);\r
- }\r
- for (i = 0; i < entriesToRemove.length; i++) {\r
- noteholder.removeChild(entriesToRemove[i]);\r
- }\r
-\r
- // Rebuild footnote entries.\r
- var cont = document.getElementById("content");\r
- var spans = cont.getElementsByTagName("span");\r
- var refs = {};\r
- var n = 0;\r
- for (i=0; i<spans.length; i++) {\r
- if (spans[i].className == "footnote") {\r
- n++;\r
- var note = spans[i].getAttribute("data-note");\r
- if (!note) {\r
- // Use [\s\S] in place of . so multi-line matches work.\r
- // Because JavaScript has no s (dotall) regex flag.\r
- note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];\r
- spans[i].innerHTML =\r
- "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +\r
- "' title='View footnote' class='footnote'>" + n + "</a>]";\r
- spans[i].setAttribute("data-note", note);\r
- }\r
- noteholder.innerHTML +=\r
- "<div class='footnote' id='_footnote_" + n + "'>" +\r
- "<a href='#_footnoteref_" + n + "' title='Return to text'>" +\r
- n + "</a>. " + note + "</div>";\r
- var id =spans[i].getAttribute("id");\r
- if (id != null) refs["#"+id] = n;\r
- }\r
- }\r
- if (n == 0)\r
- noteholder.parentNode.removeChild(noteholder);\r
- else {\r
- // Process footnoterefs.\r
- for (i=0; i<spans.length; i++) {\r
- if (spans[i].className == "footnoteref") {\r
- var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");\r
- href = href.match(/#.*/)[0]; // Because IE return full URL.\r
- n = refs[href];\r
- spans[i].innerHTML =\r
- "[<a href='#_footnote_" + n +\r
- "' title='View footnote' class='footnote'>" + n + "</a>]";\r
- }\r
- }\r
- }\r
-},\r
-\r
-install: function(toclevels) {\r
- var timerId;\r
-\r
- function reinstall() {\r
- asciidoc.footnotes();\r
- if (toclevels) {\r
- asciidoc.toc(toclevels);\r
- }\r
- }\r
-\r
- function reinstallAndRemoveTimer() {\r
- clearInterval(timerId);\r
- reinstall();\r
- }\r
-\r
- timerId = setInterval(reinstall, 500);\r
- if (document.addEventListener)\r
- document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);\r
- else\r
- window.onload = reinstallAndRemoveTimer;\r
-}\r
-\r
-}\r
-asciidoc.install(2);\r
-/*]]>*/\r
-</script>\r
-</head>\r
-<body class="article">\r
-<div id="header">\r
-<h1>ccache README</h1>\r
-<span id="revnumber">version 3.2.9</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>\r
-<div id="content">\r
-<div class="sect1">\r
-<h2 id="_about">About</h2>\r
-<div class="sectionbody">\r
-<div class="paragraph"><p>ccache is a compiler cache. It speeds up recompilation by caching the result of\r
-previous compilations and detecting when the same compilation is being done\r
-again. Supported languages are C, C<code>, Objective-C and Objective-C</code>.</p></div>\r
-<div class="paragraph"><p>Please see the manual page and documentation at <a href="http://ccache.samba.org">http://ccache.samba.org</a> for\r
-more information.</p></div>\r
-</div>\r
-</div>\r
-<div class="sect1">\r
-<h2 id="_documentation">Documentation</h2>\r
-<div class="sectionbody">\r
-<div class="paragraph"><p>See the ccache(1) man page. It’s also available as MANUAL.{txt,html}.</p></div>\r
-</div>\r
-</div>\r
-<div class="sect1">\r
-<h2 id="_installation">Installation</h2>\r
-<div class="sectionbody">\r
-<div class="paragraph"><p>See INSTALL.{txt.html}.</p></div>\r
-</div>\r
-</div>\r
-<div class="sect1">\r
-<h2 id="_web_site">Web site</h2>\r
-<div class="sectionbody">\r
-<div class="paragraph"><p>The main ccache web site is here:</p></div>\r
-<div class="literalblock">\r
-<div class="content">\r
-<pre><code>http://ccache.samba.org</code></pre>\r
-</div></div>\r
-</div>\r
-</div>\r
-<div class="sect1">\r
-<h2 id="_mailing_list">Mailing list</h2>\r
-<div class="sectionbody">\r
-<div class="paragraph"><p>There is a mailing list for discussing usage and development of ccache:</p></div>\r
-<div class="literalblock">\r
-<div class="content">\r
-<pre><code>http://lists.samba.org/mailman/listinfo/ccache/</code></pre>\r
-</div></div>\r
-<div class="paragraph"><p>Anyone is welcome to join.</p></div>\r
-</div>\r
-</div>\r
-<div class="sect1">\r
-<h2 id="_bug_reports">Bug reports</h2>\r
-<div class="sectionbody">\r
-<div class="paragraph"><p>To submit a bug report or to search for existing reports, please visit this web\r
-page:</p></div>\r
-<div class="literalblock">\r
-<div class="content">\r
-<pre><code>http://ccache.samba.org/bugs.html</code></pre>\r
-</div></div>\r
-</div>\r
-</div>\r
-<div class="sect1">\r
-<h2 id="_source_code_repository">Source code repository</h2>\r
-<div class="sectionbody">\r
-<div class="paragraph"><p>To get the very latest version of ccache directly from the source code\r
-repository, use git:</p></div>\r
-<div class="literalblock">\r
-<div class="content">\r
-<pre><code>git clone https://github.com/ccache/ccache.git</code></pre>\r
-</div></div>\r
-<div class="paragraph"><p>You can also browse the repository:</p></div>\r
-<div class="literalblock">\r
-<div class="content">\r
-<pre><code>https://github.com/ccache/ccache</code></pre>\r
-</div></div>\r
-</div>\r
-</div>\r
-<div class="sect1">\r
-<h2 id="_history">History</h2>\r
-<div class="sectionbody">\r
-<div class="paragraph"><p>ccache was originally written by Andrew Tridgell and is currently developed and\r
-maintained by Joel Rosdahl. ccache started out as a reimplementation of Erik\r
-Thiele’s “compilercache” (see <a href="http://www.erikyyy.de/compilercache/">http://www.erikyyy.de/compilercache/</a>) in C.</p></div>\r
-<div class="paragraph"><p>See also NEWS.{txt,html}.</p></div>\r
-</div>\r
-</div>\r
-<div class="sect1">\r
-<h2 id="_license_and_copyright">License and copyright</h2>\r
-<div class="sectionbody">\r
-<div class="paragraph"><p>See LICENSE.{txt,html} and AUTHORS.{txt,html}.</p></div>\r
-</div>\r
-</div>\r
-</div>\r
-<div id="footnotes"><hr /></div>\r
-<div id="footer">\r
-<div id="footer-text">\r
-Version 3.2.9<br />\r
-Last updated\r
- 2016-09-28 21:28:19 CEST\r
-</div>\r
-</div>\r
-</body>\r
-</html>\r
-ccache README
-=============
+ccache
+======
+[![Build Status](https://travis-ci.org/ccache/ccache.svg?branch=master)](https://travis-ci.org/ccache/ccache)
About
-----
previous compilations and detecting when the same compilation is being done
again. Supported languages are C, C++, Objective-C and Objective-C++.
-Please see the manual page and documentation at http://ccache.samba.org for
-more information.
-
Documentation
-------------
-See the ccache(1) man page. It's also available as MANUAL.{txt,html}.
+See the https://ccache.samba.org.
Installation
------------
-See INSTALL.{txt.html}.
+See [INSTALL.md](INSTALL.md).
Web site
The main ccache web site is here:
- http://ccache.samba.org
+https://ccache.samba.org
Mailing list
There is a mailing list for discussing usage and development of ccache:
- http://lists.samba.org/mailman/listinfo/ccache/
+https://lists.samba.org/mailman/listinfo/ccache/
Anyone is welcome to join.
To submit a bug report or to search for existing reports, please visit this web
page:
- http://ccache.samba.org/bugs.html
-
-
-Source code repository
-----------------------
-
-To get the very latest version of ccache directly from the source code
-repository, use git:
-
- git clone https://github.com/ccache/ccache.git
-
-You can also browse the repository:
-
- https://github.com/ccache/ccache
+https://ccache.samba.org/bugs.html
History
ccache was originally written by Andrew Tridgell and is currently developed and
maintained by Joel Rosdahl. ccache started out as a reimplementation of Erik
-Thiele's ``compilercache'' (see http://www.erikyyy.de/compilercache/) in C.
+Thiele's "compilercache" (see http://www.erikyyy.de/compilercache/) in C.
-See also NEWS.{txt,html}.
+See also https://ccache.samba.org/news.html.
License and copyright
---------------------
-See LICENSE.{txt,html} and AUTHORS.{txt,html}.
+See https://ccache.samba.org/license.html.
-/*
- * Copyright (C) 2002 Andrew Tridgell
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2002 Andrew Tridgell
+// Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
struct args *
args_init(int init_argc, char **init_args)
{
- struct args *args;
- int i;
- args = (struct args *)x_malloc(sizeof(struct args));
+ struct args *args = (struct args *)x_malloc(sizeof(struct args));
args->argc = 0;
args->argv = (char **)x_malloc(sizeof(char *));
args->argv[0] = NULL;
- for (i = 0; i < init_argc; i++) {
+ for (int i = 0; i < init_argc; i++) {
args_add(args, init_args[i]);
}
return args;
struct args *
args_init_from_string(const char *command)
{
- struct args *args;
char *p = x_strdup(command);
char *q = p;
char *word, *saveptr = NULL;
-
- args = args_init(0, NULL);
+ struct args *args = args_init(0, NULL);
while ((word = strtok_r(q, " \t\r\n", &saveptr))) {
args_add(args, word);
q = NULL;
struct args *
args_init_from_gcc_atfile(const char *filename)
{
- struct args *args;
- char *pos, *argtext, *argpos, *argbuf;
- char quoting;
-
- /* Used to track quoting state; if \0, we are not inside quotes. Otherwise
- * stores the quoting character that started it, for matching the end
- * quote */
- quoting = '\0';
-
- if (!(argtext = read_text_file(filename, 0)))
+ char *argtext;
+ if (!(argtext = read_text_file(filename, 0))) {
return NULL;
+ }
+
+ struct args *args = args_init(0, NULL);
+ char *pos = argtext;
+ char *argbuf = x_malloc(strlen(argtext) + 1);
+ char *argpos = argbuf;
- args = args_init(0, NULL);
- pos = argtext;
- argbuf = x_malloc(strlen(argtext) + 1);
- argpos = argbuf;
+ // Used to track quoting state; if \0, we are not inside quotes. Otherwise
+ // stores the quoting character that started it, for matching the end quote.
+ char quoting = '\0';
while (1) {
switch (*pos) {
if (quoting) {
break;
}
- /* Fall through */
+ // Fall through.
case '\0':
- /* end of token */
+ // End of token
*argpos = '\0';
- if (argbuf[0] != '\0')
+ if (argbuf[0] != '\0') {
args_add(args, argbuf);
+ }
argpos = argbuf;
if (*pos == '\0') {
goto out;
return args_init(args->argc, args->argv);
}
-/* Insert all arguments in src into dest at position index.
- * If replace is true, the element at dest->argv[index] is replaced
- * with the contents of src and everything past it is shifted.
- * Otherwise, dest->argv[index] is also shifted.
- *
- * src is consumed by this operation and should not be freed or used
- * again by the caller */
+// Insert all arguments in src into dest at position index. If replace is true,
+// the element at dest->argv[index] is replaced with the contents of src and
+// everything past it is shifted. Otherwise, dest->argv[index] is also shifted.
+//
+// src is consumed by this operation and should not be freed or used again by
+// the caller.
void
args_insert(struct args *dest, int index, struct args *src, bool replace)
{
- int offset;
- int i;
-
- /* Adjustments made if we are replacing or shifting the element
- * currently at dest->argv[index] */
- offset = replace ? 1 : 0;
+ // Adjustments made if we are replacing or shifting the element currently at
+ // dest->argv[index].
+ int offset = replace ? 1 : 0;
if (replace) {
free(dest->argv[index]);
if (src->argc == 0) {
if (replace) {
- /* Have to shift everything down by 1 since
- * we replaced with an empty list */
- for (i = index; i < dest->argc; i++) {
+ // Have to shift everything down by 1 since we replaced with an empty
+ // list.
+ for (int i = index; i < dest->argc; i++) {
dest->argv[i] = dest->argv[i + 1];
}
dest->argc--;
}
if (src->argc == 1 && replace) {
- /* Trivial case; replace with 1 element */
+ // Trivial case; replace with 1 element.
dest->argv[index] = src->argv[0];
src->argc = 0;
args_free(src);
(src->argc + dest->argc + 1 - offset) *
sizeof(char *));
- /* Shift arguments over */
- for (i = dest->argc; i >= index + offset; i--) {
+ // Shift arguments over.
+ for (int i = dest->argc; i >= index + offset; i--) {
dest->argv[i + src->argc - offset] = dest->argv[i];
}
- /* Copy the new arguments into place */
- for (i = 0; i < src->argc; i++) {
+ // Copy the new arguments into place.
+ for (int i = 0; i < src->argc; i++) {
dest->argv[i + index] = src->argv[i];
}
void
args_free(struct args *args)
{
- int i;
if (!args) {
return;
}
- for (i = 0; i < args->argc; ++i) {
+ for (int i = 0; i < args->argc; ++i) {
if (args->argv[i]) {
free(args->argv[i]);
}
args->argv[args->argc] = NULL;
}
-/* Add all arguments in to_append to args. */
+// Add all arguments in to_append to args.
void
args_extend(struct args *args, struct args *to_append)
{
- int i;
- for (i = 0; i < to_append->argc; i++) {
+ for (int i = 0; i < to_append->argc; i++) {
args_add(args, to_append->argv[i]);
}
}
-/* pop the last element off the args list */
+// Pop the last element off the args list.
void
args_pop(struct args *args, int n)
{
}
}
-/* set argument at given index */
+// Set argument at given index.
void
args_set(struct args *args, int index, const char *value)
{
args->argv[index] = x_strdup(value);
}
-/* remove the first element of the argument list */
+// Remove the first element of the argument list.
void
args_remove_first(struct args *args)
{
args->argc--;
}
-/* add an argument into the front of the argument list */
+// Add an argument into the front of the argument list.
void
args_add_prefix(struct args *args, const char *s)
{
args->argc++;
}
-/* strip any arguments beginning with the specified prefix */
+// Strip any arguments beginning with the specified prefix.
void
args_strip(struct args *args, const char *prefix)
{
- int i;
- for (i = 0; i < args->argc; ) {
+ for (int i = 0; i < args->argc; ) {
if (str_startswith(args->argv[i], prefix)) {
free(args->argv[i]);
memmove(&args->argv[i],
}
}
-/*
- * Format args to a space-separated string. Does not quote spaces. Caller
- * frees.
- */
+// Format args to a space-separated string. Does not quote spaces. Caller
+// frees.
char *
args_to_string(struct args *args)
{
- char *result;
- char **p;
unsigned size = 0;
- int pos;
- for (p = args->argv; *p; p++) {
+ for (char **p = args->argv; *p; p++) {
size += strlen(*p) + 1;
}
- result = x_malloc(size + 1);
- pos = 0;
- for (p = args->argv; *p; p++) {
+
+ char *result = x_malloc(size + 1);
+ int pos = 0;
+ for (char **p = args->argv; *p; p++) {
pos += sprintf(&result[pos], "%s ", *p);
}
result[pos - 1] = '\0';
return result;
}
-/* Returns true if args1 equals args2, else false. */
+// Returns true if args1 equals args2, else false.
bool
args_equal(struct args *args1, struct args *args2)
{
- int i;
if (args1->argc != args2->argc) {
return false;
}
- for (i = 0; i < args1->argc; i++) {
+ for (int i = 0; i < args1->argc; i++) {
if (!str_eq(args1->argv[i], args2->argv[i])) {
return false;
}
}
return true;
}
-
.\" Title: ccache
.\" Author: [see the "Author" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 09/28/2016
+.\" Date: 08/27/2016
.\" Manual: ccache Manual
-.\" Source: ccache 3.2.9
+.\" Source: ccache 3.3
.\" Language: English
.\"
-.TH "CCACHE" "1" "09/28/2016" "ccache 3\&.2\&.9" "ccache Manual"
+.TH "CCACHE" "1" "08/27/2016" "ccache 3\&.3" "ccache Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.sp
ccache is a compiler cache\&. It speeds up recompilation by caching the result of previous compilations and detecting when the same compilation is being done again\&. Supported languages are C, C++, Objective\-C and Objective\-C++\&.
.sp
-ccache has been carefully written to always produce exactly the same compiler output that you would get without the cache\&. The only way you should be able to tell that you are using ccache is the speed\&. Currently known exceptions to this goal are listed under BUGS\&. If you ever discover an undocumented case where ccache changes the output of your compiler, please let us know\&.
+ccache has been carefully written to always produce exactly the same compiler output that you would get without the cache\&. The only way you should be able to tell that you are using ccache is the speed\&. Currently known exceptions to this goal are listed under CAVEATS\&. If you ever discover an undocumented case where ccache changes the output of your compiler, please let us know\&.
.SS "Features"
.sp
.RS 4
\fBbase_dir\fR (\fBCCACHE_BASEDIR\fR)
.RS 4
This setting should be an absolute path to a directory\&. ccache then rewrites absolute paths into relative paths before computing the hash that identifies the compilation, but only for paths under the specified directory\&. If set to the empty string (which is the default), no rewriting is done\&. See also the discussion under
-COMPILING IN DIFFERENT DIRECTORIES\&.
+COMPILING IN DIFFERENT DIRECTORIES\&. If using GCC or newer versions of Clang, you might want to look into the
+\fB\-fdebug\-prefix\-map=old=new\fR
+option for relocating debug info to a common prefix (mapping prefix with old=new)\&.
.RE
.PP
\fBcache_dir\fR (\fBCCACHE_DIR\fR)
.PP
\fBextra_files_to_hash\fR (\fBCCACHE_EXTRAFILES\fR)
.RS 4
-This setting is a list of paths to files that ccache will include in the the hash sum that idetifies the build\&. The list separator is semicolon on Windows systems and colon on other systems\&.
+This setting is a list of paths to files that ccache will include in the the hash sum that identifies the build\&. The list separator is semicolon on Windows systems and colon on other systems\&.
.RE
.PP
\fBhard_link\fR (\fBCCACHE_HARDLINK\fR or \fBCCACHE_NOHARDLINK\fR, see Boolean values above)
.PP
\fBhash_dir\fR (\fBCCACHE_HASHDIR\fR or \fBCCACHE_NOHASHDIR\fR, see Boolean values above)
.RS 4
-If true, ccache will include the current working directory in the hash that is used to distinguish two compilations\&. This prevents a problem with the storage of the current working directory in the debug info of an object file, which can lead ccache to give a cached object file that has the working directory in the debug info set incorrectly\&. This option is off by default as the incorrect setting of this debug info rarely causes problems\&. If you strike problems with GDB not using the correct directory then enable this option\&.
+If true (which is the default), ccache will include the current working directory (CWD) in the hash that is used to distinguish two compilations when generating debug info (compiler option
+\fB\-g\fR
+with variations)\&. Exception: The CWD will not be included in the hash if
+\fBbase_dir\fR
+is set (and matches the CWD) and the compiler option
+\fB\-fdebug\-prefix\-map\fR
+is used\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+The reason for including the CWD in the hash by default is to prevent a
+problem with the storage of the current working directory in the debug info
+of an object file, which can lead ccache to return a cached object file
+that has the working directory in the debug info set incorrectly\&.
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+You can disable this setting to get cache hits when compiling the same
+source code in different directories if you don\*(Aqt mind that CWD in the
+debug info might be incorrect\&.
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.PP
+\fBignore_headers_in_manifest\fR (\fBCCACHE_IGNOREHEADERS\fR)
+.RS 4
+This setting is a list of paths to files (or directories with headers) that ccache will
+\fBnot\fR
+include in the manifest list that makes up the direct mode\&. Note that this can cause stale cache hits if those headers do indeed change\&. The list separator is semicolon on Windows systems and colon on other systems\&.
+.RE
+.PP
+\fBkeep_comments_cpp\fR (\fBCCACHE_COMMENTS\fR or \fBCCACHE_NOCOMMENTS\fR, see Boolean values above)
+.RS 4
+If true, ccache will not discard the comments before hashing preprocessor output\&. This can be used to check documentation with
+\fB\-Wdocumentation\fR\&.
+.RE
+.PP
+\fBlimit_multiple\fR (\fBCCACHE_LIMIT_MULTIPLE\fR)
+.RS 4
+Sets the limit when cleaning up\&. Files are deleted (in LRU order) until the levels are below the limit\&. The default is 0\&.8 (= 80%)\&.
.RE
.PP
\fBlog_file\fR (\fBCCACHE_LOGFILE\fR)
USING CCACHE WITH OTHER COMPILER WRAPPERS\&.
.RE
.PP
+\fBprefix_command_cpp\fR (\fBCCACHE_PREFIX_CPP\fR)
+.RS 4
+This option adds a list of prefixes (separated by space) to the command line that ccache uses when invoking the preprocessor\&.
+.RE
+.PP
\fBread_only\fR (\fBCCACHE_READONLY\fR or \fBCCACHE_NOREADONLY\fR, see Boolean values above)
.RS 4
If true, ccache will attempt to use existing cached object files, but it will not to try to add anything new to the cache\&. If you are using this because your ccache directory is read\-only, then you need to set
.PP
\fBrun_second_cpp\fR (\fBCCACHE_CPP2\fR or \fBCCACHE_NOCPP2\fR, see Boolean values above)
.RS 4
-If true, ccache will not use the optimisation of avoiding the second call to the preprocessor by compiling the preprocessed output that was used for finding the hash in the case of a cache miss\&. This is primarily a debugging option, although it is possible that some unusual compilers will have problems with compiling the preprocessed output, in which case this option could allow ccache to be used anyway\&.
+If true, ccache will first run the preprocessor to preprocess the source code (see
+THE PREPROCESSOR MODE) and then on a cache miss run the compiler on the source code to get hold of the object file\&. This is the default\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+If false, ccache will first run preprocessor to preprocess the source code
+and then on a cache miss run the compiler on the _preprocessed source code_
+instead of the original source code\&. This makes cache misses slightly
+faster since the source code only has to be preprocessed once\&. The downside
+is that some compilers won\*(Aqt produce the same result (for instance
+diagnostics warnings) when compiling preprocessed source code\&.
+.fi
+.if n \{\
+.RE
+.\}
.RE
.PP
\fBsloppiness\fR (\fBCCACHE_SLOPPINESS\fR)
By default, ccache will not cache a file if it includes a header whose mtime is too new\&. This option disables that check\&.
.RE
.PP
+\fBno_system_headers\fR
+.RS 4
+By default, ccache will also include all system headers in the manifest\&. With this option set, ccache will only include system headers in the hash but not add the system header files to the list of include files\&.
+.RE
+.PP
\fBpch_defines\fR
.RS 4
Be sloppy about #defines when precompiling a header file\&. See
a
\fB\-Wp,\fR\fB\fIX\fR\fR
compiler option other than
-\fB\-Wp,\-MD,\fR\fB\fIpath\fR\fR
-and
+\fB\-Wp,\-MD,\fR\fB\fIpath\fR\fR,
\fB\-Wp,\-MMD,\fR\fB\fIpath\fR\fR
+and
+\fB\-Wp,\-D_define_\fR
.RE
.sp
.RS 4
The cached results will not be shared between compilations with and without the other wrapper\&.
.RE
.sp
-Another minor thing is that if \fBprefix_command\fR is used, ccache will not invoke the other wrapper when running the preprocessor, which increase performance\&.
-.SH "BUGS"
+Another minor thing is that if \fBprefix_command\fR is used, ccache will not invoke the other wrapper when running the preprocessor, which increases performance\&. You can use the \fBprefix_command_cpp\fR configuration setting if you also want to invoke the other wrapper when doing preprocessing (normally by adding \fB\-E\fR)\&.
+.SH "CAVEATS"
.sp
.RS 4
.ie n \{\
.sp
ccache has been written to perform well out of the box, but sometimes you may have to do some adjustments of how you use the compiler and ccache in order to improve performance\&.
.sp
-Since ccache works best when I/O is fast, put the cache directory on a fast storage device if possible\&. Having lots of free memory so that files in the cache directory stay in the disk cache is also preferrable\&.
+Since ccache works best when I/O is fast, put the cache directory on a fast storage device if possible\&. Having lots of free memory so that files in the cache directory stay in the disk cache is also preferable\&.
.sp
A good way of monitoring how well ccache works is to run \fBccache \-s\fR before and after your build and then compare the statistics counters\&. Here are some common problems and what may be done to increase the hit rate:
.sp
or
\fB\-Wp,\fR\fB\fIX\fR\fR
(except
-\fB\-Wp,\-MD,\fR\fB\fIpath\fR\fR
-and
-\fBWp,\-MMD,\fR\fB\fIpath\fR\fR) is used\&.
+\fB\-Wp,\-MD,\fR\fB\fIpath\fR\fR,
+\fB\-Wp,\-MMD,\fR\fB\fIpath\fR\fR, and
+\fB\-Wp,\-D_define_\fR) is used\&.
.RE
.sp
.RS 4
If \(lqcan\(cqt use precompiled header\(rq has been incremented, see
PRECOMPILED HEADERS\&.
.RE
-.SS "Errors when compiling with ccache"
-.sp
-If compilation doesn\(cqt work with ccache, but it works without it, one possible reason is that the compiler can\(cqt compile preprocessed output correctly\&. A workaround that may work is to enable \fBrun_second_cpp\fR*\&. This will make cache misses slower, though, so it is better to find and fix the root cause\&.
.SS "Corrupt object files"
.sp
It should be noted that ccache is susceptible to general storage problems\&. If a bad object file sneaks into the cache for some reason, it will of course stay bad\&. Some possible reasons for erroneous object files are bad hardware (disk drive, disk controller, memory, etc), buggy drivers or file systems, a bad \fBprefix_command\fR or compiler wrapper\&. If this happens, the easiest way of fixing it is this:
There are no reported issues about ccache producing broken object files reproducibly\&. That doesn\(cqt mean it can\(cqt happen, so if you find a repeatable case, please report it\&.
.SH "MORE INFORMATION"
.sp
-Credits, mailing list information, bug reporting instructions, source code, etc, can be found on ccache\(cqs web site: http://ccache\&.samba\&.org\&.
+Credits, mailing list information, bug reporting instructions, source code, etc, can be found on ccache\(cqs web site: https://ccache\&.samba\&.org\&.
.SH "AUTHOR"
.sp
-ccache was originally written by Andrew Tridgell and is currently developed and maintained by Joel Rosdahl\&. See AUTHORS\&.txt or AUTHORS\&.html and http://ccache\&.samba\&.org/credits\&.html for a list of contributors\&.
+ccache was originally written by Andrew Tridgell and is currently developed and maintained by Joel Rosdahl\&. See AUTHORS\&.txt or AUTHORS\&.html and https://ccache\&.samba\&.org/credits\&.html for a list of contributors\&.
-/*
- * ccache -- a fast C/C++ compiler cache
- *
- * Copyright (C) 2002-2007 Andrew Tridgell
- * Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// ccache -- a fast C/C++ compiler cache
+//
+// Copyright (C) 2002-2007 Andrew Tridgell
+// Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
#include "compopt.h"
" -h, --help print this help text\n"
" -V, --version print version and copyright information\n"
"\n"
- "See also <http://ccache.samba.org>.\n";
+ "See also <https://ccache.samba.org>.\n";
-/* Global configuration data. */
+// Global configuration data.
struct conf *conf = NULL;
-/* Where to write configuration changes. */
+// Where to write configuration changes.
char *primary_config_path = NULL;
-/* Secondary, read-only configuration file (if any). */
+// Secondary, read-only configuration file (if any).
char *secondary_config_path = NULL;
-/* current working directory taken from $PWD, or getcwd() if $PWD is bad */
+// Current working directory taken from $PWD, or getcwd() if $PWD is bad.
char *current_working_dir = NULL;
-/* the original argument list */
+// The original argument list.
static struct args *orig_args;
-/* the source file */
+// The source file.
static char *input_file;
-/* The output file being compiled to. */
+// The output file being compiled to.
static char *output_obj;
-/* The path to the dependency file (implicit or specified with -MF). */
+// 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). */
+// The path to the coverage file (implicit when using -ftest-coverage).
static char *output_cov;
-/* Diagnostic generation information (clang). Contains pathname if not
- * NULL. */
+// Diagnostic generation information (clang). Contains pathname if not NULL.
static char *output_dia = NULL;
-/* -gsplit-dwarf support: Split dwarf information (GCC 4.8 and
- * up). Contains pathname if not NULL. */
+// Split dwarf information (GCC 4.8 andup). Contains pathname if not NULL.
static char *output_dwo = NULL;
-/*
- * Name (represented as a struct file_hash) of the file containing the cached
- * object code.
- */
+// Array for storing -arch options.
+#define MAX_ARCH_ARGS 10
+static size_t arch_args_size = 0;
+static char *arch_args[MAX_ARCH_ARGS] = {NULL};
+
+// Name (represented as a struct file_hash) of the file containing the cached
+// object code.
static struct file_hash *cached_obj_hash;
-/*
- * Full path to the file containing the cached object code
- * (cachedir/a/b/cdef[...]-size.o).
- */
+// Full path to the file containing the cached object code
+// (cachedir/a/b/cdef[...]-size.o).
static char *cached_obj;
-/*
- * Full path to the file containing the standard error output
- * (cachedir/a/b/cdef[...]-size.stderr).
- */
+// Full path to the file containing the standard error output
+// (cachedir/a/b/cdef[...]-size.stderr).
static char *cached_stderr;
-/*
- * Full path to the file containing the dependency information
- * (cachedir/a/b/cdef[...]-size.d).
- */
+// Full path to the file containing the dependency information
+// (cachedir/a/b/cdef[...]-size.d).
static char *cached_dep;
-/*
- * Full path to the file containing the coverage information
- * (cachedir/a/b/cdef[...]-size.gcno).
- */
+// 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).
- */
+// Full path to the file containing the diagnostic information (for clang)
+// (cachedir/a/b/cdef[...]-size.dia).
static char *cached_dia;
-/*
- * -gsplit-dwarf support:
- * Full path to the file containing the split dwarf (for GCC 4.8 and
- * above)
- * (cachedir/a/b/cdef[...]-size.dwo).
- *
- * contains NULL if -gsplit-dwarf is not given.
- */
+// Full path to the file containing the split dwarf (for GCC 4.8 and above)
+// (cachedir/a/b/cdef[...]-size.dwo).
+//
+// Contains NULL if -gsplit-dwarf is not given.
static char *cached_dwo;
-/*
- * -gsplit-dwarf support:
- * using_split_dwarf is true if "-gsplit-dwarf" is given to the
- * compiler (GCC 4.8 and up).
- */
+// using_split_dwarf is true if "-gsplit-dwarf" is given to the compiler (GCC
+// 4.8 and up).
bool using_split_dwarf = false;
-/*
- * Full path to the file containing the manifest
- * (cachedir/a/b/cdef[...]-size.manifest).
- */
+// Full path to the file containing the manifest
+// (cachedir/a/b/cdef[...]-size.manifest).
static char *manifest_path;
-/*
- * Time of compilation. Used to see if include files have changed after
- * compilation.
- */
+// Time of compilation. Used to see if include files have changed after
+// compilation.
time_t time_of_compilation;
-/*
- * Files included by the preprocessor and their hashes/sizes. Key: file path.
- * Value: struct file_hash.
- */
-static struct hashtable *included_files;
+// Files included by the preprocessor and their hashes/sizes. Key: file path.
+// Value: struct file_hash.
+static struct hashtable *included_files = NULL;
+
+// Uses absolute path for some include files.
+static bool has_absolute_include_headers = false;
+
+// List of headers to ignore.
+static char **ignore_headers;
-/* is gcc being asked to output dependencies? */
+// Size of headers to ignore list.
+static size_t ignore_headers_len;
+
+// Is the compiler being asked to output debug info?
+static bool generating_debuginfo;
+
+// Is the compiler being asked to output dependencies?
static bool generating_dependencies;
-/* is gcc being asked to output coverage? */
+// Is the compiler being asked to output coverage?
static bool generating_coverage;
-/* is gcc being asked to output coverage data (.gcda) at runtime? */
+// Relocating debuginfo in the format old=new.
+static char *debug_prefix_map = NULL;
+
+// Is the compiler being asked to output coverage data (.gcda) at runtime?
static bool profile_arcs;
-/* name of the custom profile directory (default: object dirname) */
+// Name of the custom profile directory (default: object dirname).
static char *profile_dir;
-/* the name of the temporary pre-processor file */
+// The name of the temporary preprocessed file.
static char *i_tmpfile;
-/* are we compiling a .i or .ii file directly? */
+// Are we compiling a .i or .ii file directly?
static bool direct_i_file;
-/* the name of the cpp stderr file */
+// The name of the cpp stderr file.
static char *cpp_stderr;
-/*
- * Full path to the statistics file in the subdirectory where the cached result
- * belongs (<cache_dir>/<x>/stats).
- */
+// Full path to the statistics file in the subdirectory where the cached result
+// belongs (<cache_dir>/<x>/stats).
char *stats_file = NULL;
-/* Whether the output is a precompiled header */
+// Whether the output is a precompiled header.
static bool output_is_precompiled_header = false;
-/* Profile generation / usage information */
+// Profile generation / usage information.
static char *profile_dir = NULL;
static bool profile_use = false;
static bool profile_generate = false;
-/*
- * Whether we are using a precompiled header (either via -include, #include or
- * clang's -include-pch or -include-pth).
- */
+// Whether we are using a precompiled header (either via -include, #include or
+// clang's -include-pch or -include-pth).
static bool using_precompiled_header = false;
-/*
- * The .gch/.pch/.pth file used for compilation.
- */
+// The .gch/.pch/.pth file used for compilation.
static char *included_pch_file = NULL;
-/* How long (in microseconds) to wait before breaking a stale lock. */
+// How long (in microseconds) to wait before breaking a stale lock.
unsigned lock_staleness_limit = 2000000;
enum fromcache_call_mode {
struct pending_tmp_file *next;
};
-/* Temporary files to remove at program exit. */
+// Temporary files to remove at program exit.
static struct pending_tmp_file *pending_tmp_files = NULL;
+#ifndef _WIN32
static sigset_t fatal_signal_set;
-/* PID of currently executing compiler that we have started, if any. 0 means no
- * ongoing compilation. */
+// PID of currently executing compiler that we have started, if any. 0 means no
+// ongoing compilation.
static pid_t compiler_pid = 0;
+#endif
-/*
- * This is a string that identifies the current "version" of the hash sum
- * computed by ccache. If, for any reason, we want to force the hash sum to be
- * different for the same input in a new ccache version, we can just change
- * this string. A typical example would be if the format of one of the files
- * stored in the cache changes in a backwards-incompatible way.
- */
+// This is a string that identifies the current "version" of the hash sum
+// computed by ccache. If, for any reason, we want to force the hash sum to be
+// different for the same input in a new ccache version, we can just change
+// this string. A typical example would be if the format of one of the files
+// stored in the cache changes in a backwards-incompatible way.
static const char HASH_PREFIX[] = "3";
static void
-add_prefix(struct args *args)
+add_prefix(struct args *args, char *prefix_command)
{
- char *e;
- char *tok, *saveptr = NULL;
- struct args *prefix;
- int i;
-
- if (str_eq(conf->prefix_command, "")) {
+ if (str_eq(prefix_command, "")) {
return;
}
- prefix = args_init(0, NULL);
- e = x_strdup(conf->prefix_command);
- for (tok = strtok_r(e, " ", &saveptr);
+ struct args *prefix = args_init(0, NULL);
+ char *e = x_strdup(prefix_command);
+ char *saveptr = NULL;
+ for (char *tok = strtok_r(e, " ", &saveptr);
tok;
tok = strtok_r(NULL, " ", &saveptr)) {
char *p;
}
free(e);
- cc_log("Using command-line prefix %s", conf->prefix_command);
- for (i = prefix->argc; i != 0; i--) {
+ cc_log("Using command-line prefix %s", prefix_command);
+ for (int i = prefix->argc; i != 0; i--) {
args_add_prefix(args, prefix->argv[i-1]);
}
args_free(prefix);
}
-/* Something went badly wrong - just execute the real compiler. */
+// Something went badly wrong - just execute the real compiler.
static void
failed(void)
{
assert(orig_args);
args_strip(orig_args, "--ccache-");
- add_prefix(orig_args);
+ add_prefix(orig_args, conf->prefix_command);
cc_log("Failed; falling back to running the real compiler");
cc_log_argv("Executing ", orig_args->argv);
{
static char *path = NULL;
if (path) {
- return path; /* Memoize */
+ return path; // Memoize
}
path = conf->temporary_dir;
if (str_eq(path, "")) {
void
block_signals(void)
{
+#ifndef _WIN32
sigprocmask(SIG_BLOCK, &fatal_signal_set, NULL);
+#endif
}
void
unblock_signals(void)
{
+#ifndef _WIN32
sigset_t empty;
sigemptyset(&empty);
sigprocmask(SIG_SETMASK, &empty, NULL);
+#endif
}
static void
add_pending_tmp_file(const char *path)
{
- struct pending_tmp_file *e;
-
block_signals();
- e = x_malloc(sizeof(*e));
+ struct pending_tmp_file *e = x_malloc(sizeof(*e));
e->path = x_strdup(path);
e->next = pending_tmp_files;
pending_tmp_files = e;
{
struct pending_tmp_file *p = pending_tmp_files;
while (p) {
- /* Can't call tmp_unlink here since its cc_log calls aren't signal safe. */
+ // 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. */
+ // Leak p->path and p here because clean_up_pending_tmp_files needs to be
+ // signal safe.
}
}
unblock_signals();
}
+#ifndef _WIN32
static void
signal_handler(int signum)
{
- /* Unregister handler for this signal so that we can send the signal to
- * ourselves at the end of the handler. */
+ // Unregister handler for this signal so that we can send the signal to
+ // ourselves at the end of the handler.
signal(signum, SIG_DFL);
- /* If ccache was killed explicitly, then bring the compiler subprocess (if
- * any) with us as well. */
+ // If ccache was killed explicitly, then bring the compiler subprocess (if
+ // any) with us as well.
if (signum == SIGTERM
&& compiler_pid != 0
&& waitpid(compiler_pid, NULL, WNOHANG) == 0) {
do_clean_up_pending_tmp_files();
if (compiler_pid != 0) {
- /* Wait for compiler subprocess to exit before we snuff it. */
+ // Wait for compiler subprocess to exit before we snuff it.
waitpid(compiler_pid, NULL, 0);
}
- /* Resend signal to ourselves to exit properly after returning from the
- * handler. */
+ // Resend signal to ourselves to exit properly after returning from the
+ // handler.
kill(getpid(), signum);
}
register_signal_handler(SIGQUIT);
#endif
}
+#endif // _WIN32
static void
clean_up_internal_tempdir(void)
{
- DIR *dir;
- struct dirent *entry;
- struct stat st;
time_t now = time(NULL);
-
+ struct stat st;
if (x_stat(conf->cache_dir, &st) != 0 || st.st_mtime + 3600 >= now) {
- /* No cleanup needed. */
+ // No cleanup needed.
return;
}
update_mtime(conf->cache_dir);
- dir = opendir(temp_dir());
+ DIR *dir = opendir(temp_dir());
if (!dir) {
return;
}
+ struct dirent *entry;
while ((entry = readdir(dir))) {
- char *path;
-
if (str_eq(entry->d_name, ".") || str_eq(entry->d_name, "..")) {
continue;
}
- path = format("%s/%s", temp_dir(), entry->d_name);
+ char *path = format("%s/%s", temp_dir(), entry->d_name);
if (x_lstat(path, &st) == 0 && st.st_mtime + 3600 < now) {
tmp_unlink(path);
}
return current_working_dir;
}
-/*
- * Transform a name to a full path into the cache directory, creating needed
- * sublevels if needed. Caller frees.
- */
+// Transform a name to a full path into the cache directory, creating needed
+// sublevels if needed. Caller frees.
static char *
get_path_in_cache(const char *name, const char *suffix)
{
- unsigned i;
- char *path;
- char *result;
-
- path = x_strdup(conf->cache_dir);
- for (i = 0; i < conf->cache_dir_levels; ++i) {
+ char *path = x_strdup(conf->cache_dir);
+ for (unsigned i = 0; i < conf->cache_dir_levels; ++i) {
char *p = format("%s/%c", path, name[i]);
free(path);
path = p;
}
- result = format("%s/%s%s", path, name + conf->cache_dir_levels, suffix);
+ char *result =
+ format("%s/%s%s", path, name + conf->cache_dir_levels, suffix);
free(path);
return result;
}
-/*
- * This function hashes an include file and stores the path and hash in the
- * global included_files variable. If the include file is a PCH, cpp_hash is
- * also updated. Takes over ownership of path.
- */
+// This function hashes an include file and stores the path and hash in the
+// global included_files variable. If the include file is a PCH, cpp_hash is
+// also updated. Takes over ownership of path.
static void
-remember_include_file(char *path, struct mdfour *cpp_hash)
+remember_include_file(char *path, struct mdfour *cpp_hash, bool system)
{
-#ifdef _WIN32
- DWORD attributes;
-#endif
- struct mdfour fhash;
- struct stat st;
- char *source = NULL;
- size_t size;
- bool is_pch;
size_t path_len = strlen(path);
-
if (path_len >= 2 && (path[0] == '<' && path[path_len - 1] == '>')) {
- /* Typically <built-in> or <command-line>. */
+ // Typically <built-in> or <command-line>.
goto ignore;
}
if (str_eq(path, input_file)) {
- /* Don't remember the input file. */
+ // Don't remember the input file.
+ goto ignore;
+ }
+
+ if (system && (conf->sloppiness & SLOPPY_NO_SYSTEM_HEADERS)) {
+ // Don't remember this system header.
goto ignore;
}
if (hashtable_search(included_files, path)) {
- /* Already known include file. */
+ // Already known include file.
goto ignore;
}
#ifdef _WIN32
- /* stat fails on directories on win32 */
- attributes = GetFileAttributes(path);
+ // stat fails on directories on win32.
+ DWORD attributes = GetFileAttributes(path);
if (attributes != INVALID_FILE_ATTRIBUTES &&
- attributes & FILE_ATTRIBUTE_DIRECTORY)
+ attributes & FILE_ATTRIBUTE_DIRECTORY) {
goto ignore;
+ }
#endif
+ struct stat st;
if (x_stat(path, &st) != 0) {
goto failure;
}
if (S_ISDIR(st.st_mode)) {
- /* Ignore directory, typically $PWD. */
+ // Ignore directory, typically $PWD.
goto ignore;
}
if (!S_ISREG(st.st_mode)) {
- /* Device, pipe, socket or other strange creature. */
+ // Device, pipe, socket or other strange creature.
cc_log("Non-regular include file %s", path);
goto failure;
}
- /* Let's hash the include file. */
+ // Canonicalize path for comparison; clang uses ./header.h.
+ char *canonical = path;
+ size_t canonical_len = path_len;
+ if (canonical[0] == '.' && canonical[1] == '/') {
+ canonical += 2;
+ canonical_len -= 2;
+ }
+
+ for (size_t i = 0; i < ignore_headers_len; i++) {
+ char *ignore = ignore_headers[i];
+ size_t ignore_len = strlen(ignore);
+ if (ignore_len > canonical_len) {
+ continue;
+ }
+ if (strncmp(canonical, ignore, ignore_len) == 0
+ && (ignore[ignore_len-1] == DIR_DELIM_CH
+ || canonical[ignore_len] == DIR_DELIM_CH
+ || canonical[ignore_len] == '\0')) {
+ goto ignore;
+ }
+ }
+
+ // Let's hash the include file.
if (!(conf->sloppiness & SLOPPY_INCLUDE_FILE_MTIME)
&& st.st_mtime >= time_of_compilation) {
cc_log("Include file %s too new", path);
goto failure;
}
+ struct mdfour fhash;
hash_start(&fhash);
- is_pch = is_precompiled_header(path);
+ bool is_pch = is_precompiled_header(path);
if (is_pch) {
- struct file_hash pch_hash;
if (!hash_file(&fhash, path)) {
goto failure;
}
+ struct file_hash pch_hash;
hash_result_as_bytes(&fhash, pch_hash.hash);
pch_hash.size = fhash.totalN;
hash_delimiter(cpp_hash, "pch_hash");
hash_buffer(cpp_hash, pch_hash.hash, sizeof(pch_hash.hash));
}
- if (conf->direct_mode) {
- struct file_hash *h;
-
- if (!is_pch) { /* else: the file has already been hashed. */
- int result;
+ if (conf->direct_mode) {
+ if (!is_pch) { // else: the file has already been hashed.
+ char *source = NULL;
+ size_t size;
if (st.st_size > 0) {
if (!read_file(path, st.st_size, &source, &size)) {
goto failure;
size = 0;
}
- result = hash_source_code_string(conf, &fhash, source, size, path);
+ int result = hash_source_code_string(conf, &fhash, source, size, path);
+ free(source);
if (result & HASH_SOURCE_CODE_ERROR
|| result & HASH_SOURCE_CODE_FOUND_TIME) {
goto failure;
}
}
- h = x_malloc(sizeof(*h));
+ struct file_hash *h = x_malloc(sizeof(*h));
hash_result_as_bytes(&fhash, h->hash);
h->size = fhash.totalN;
hashtable_insert(included_files, path, h);
free(path);
}
- free(source);
return;
failure:
cc_log("Disabling direct mode");
conf->direct_mode = false;
}
- /* Fall through. */
+ // Fall through.
ignore:
free(path);
- free(source);
}
-/*
- * Make a relative path from current working directory to path if path is under
- * the base directory. Takes over ownership of path. Caller frees.
- */
+// Make a relative path from current working directory to path if path is under
+// the base directory. Takes over ownership of path. Caller frees.
static char *
make_relative_path(char *path)
{
- char *canon_path, *path_suffix = NULL;
- struct stat st;
-
if (str_eq(conf->base_dir, "") || !str_startswith(path, conf->base_dir)) {
return path;
}
- /* x_realpath only works for existing paths, so if path doesn't exist, try
- * dirname(path) and assemble the path afterwards. We only bother to try
- * canonicalizing one of these two paths since a compiler path argument
- * typically only makes sense if path or dirname(path) exists. */
+#ifdef _WIN32
+ if (path[0] == '/') {
+ path++; // Skip leading slash.
+ }
+#endif
+
+ // x_realpath only works for existing paths, so if path doesn't exist, try
+ // dirname(path) and assemble the path afterwards. We only bother to try
+ // canonicalizing one of these two paths since a compiler path argument
+ // typically only makes sense if path or dirname(path) exists.
+ char *path_suffix = NULL;
+ struct stat st;
if (stat(path, &st) != 0) {
- /* path doesn't exist. */
- char *dir, *p;
- dir = dirname(path);
+ // path doesn't exist.
+ char *dir = dirname(path);
if (stat(dir, &st) != 0) {
- /* And neither does its parent directory, so no action to take. */
+ // And neither does its parent directory, so no action to take.
free(dir);
return path;
}
+ free(dir);
path_suffix = basename(path);
- p = path;
+ char *p = path;
path = dirname(path);
free(p);
}
- canon_path = x_realpath(path);
+ char *canon_path = x_realpath(path);
if (canon_path) {
- char *relpath;
free(path);
- relpath = get_relative_path(get_current_working_dir(), canon_path);
+ char *relpath = get_relative_path(get_current_working_dir(), canon_path);
free(canon_path);
if (path_suffix) {
path = format("%s/%s", relpath, path_suffix);
return relpath;
}
} else {
- /* path doesn't exist, so leave it as it is. */
+ // path doesn't exist, so leave it as it is.
free(path_suffix);
return path;
}
}
-/*
- * This function reads and hashes a file. While doing this, it also does these
- * things:
- *
- * - Makes include file paths for which the base directory is a prefix relative
- * when computing the hash sum.
- * - Stores the paths and hashes of included files in the global variable
- * included_files.
- */
+// This function reads and hashes a file. While doing this, it also does these
+// things:
+//
+// - Makes include file paths for which the base directory is a prefix relative
+// when computing the hash sum.
+// - Stores the paths and hashes of included files in the global variable
+// included_files.
static bool
process_preprocessed_file(struct mdfour *hash, const char *path)
{
char *data;
- char *p, *q, *end;
size_t size;
-
if (!read_file(path, 0, &data, &size)) {
return false;
}
- included_files = create_hashtable(1000, hash_from_string, strings_equal);
+ ignore_headers = NULL;
+ ignore_headers_len = 0;
+ if (!str_eq(conf->ignore_headers_in_manifest, "")) {
+ char *header, *p, *q, *saveptr = NULL;
+ p = x_strdup(conf->ignore_headers_in_manifest);
+ q = p;
+ while ((header = strtok_r(q, PATH_DELIM, &saveptr))) {
+ ignore_headers = x_realloc(ignore_headers,
+ (ignore_headers_len+1) * sizeof(char *));
+ ignore_headers[ignore_headers_len++] = x_strdup(header);
+ q = NULL;
+ }
+ free(p);
+ }
- /* Bytes between p and q are pending to be hashed. */
- end = data + size;
- p = data;
- q = data;
- /* There must be at least 7 characters (# 1 "x") left to potentially find an
- * include file path. */
+ if (!included_files) {
+ included_files = create_hashtable(1000, hash_from_string, strings_equal);
+ }
+
+ // Bytes between p and q are pending to be hashed.
+ char *p = data;
+ char *q = data;
+ char *end = data + size;
+
+ // There must be at least 7 characters (# 1 "x") left to potentially find an
+ // include file path.
while (q < end - 7) {
- /*
- * Check if we look at a line containing the file name of an included file.
- * At least the following formats exist (where N is a positive integer):
- *
- * GCC:
- *
- * # N "file"
- * # N "file" N
- * #pragma GCC pch_preprocess "file"
- *
- * HP's compiler:
- *
- * #line N "file"
- *
- * AIX's compiler:
- *
- * #line N "file"
- * #line N
- *
- * Note that there may be other lines starting with '#' left after
- * preprocessing as well, for instance "# pragma".
- */
+ // Check if we look at a line containing the file name of an included file.
+ // At least the following formats exist (where N is a positive integer):
+ //
+ // GCC:
+ //
+ // # N "file"
+ // # N "file" N
+ // #pragma GCC pch_preprocess "file"
+ //
+ // HP's compiler:
+ //
+ // #line N "file"
+ //
+ // AIX's compiler:
+ //
+ // #line N "file"
+ // #line N
+ //
+ // Note that there may be other lines starting with '#' left after
+ // preprocessing as well, for instance "# pragma".
if (q[0] == '#'
- /* GCC: */
+ // GCC:
&& ((q[1] == ' ' && q[2] >= '0' && q[2] <= '9')
- /* GCC precompiled header: */
+ // GCC precompiled header:
|| (q[1] == 'p'
&& str_startswith(&q[2], "ragma GCC pch_preprocess "))
- /* HP/AIX: */
+ // HP/AIX:
|| (q[1] == 'l' && q[2] == 'i' && q[3] == 'n' && q[4] == 'e'
&& q[5] == ' '))
&& (q == data || q[-1] == '\n')) {
- char *path;
-
- /* Workarounds for preprocessor linemarker bugs in GCC version 6 */
+ // Workarounds for preprocessor linemarker bugs in GCC version 6.
if (q[2] == '3') {
if (str_startswith(q, "# 31 \"<command-line>\"\n")) {
- /* Bogus extra line with #31, after the regular #1:
- Ignore the whole line, and continue parsing */
+ // Bogus extra line with #31, after the regular #1: Ignore the whole
+ // line, and continue parsing.
hash_buffer(hash, p, q - p);
while (q < end && *q != '\n') {
q++;
p = q;
continue;
} else if (str_startswith(q, "# 32 \"<command-line>\" 2\n")) {
- /* Bogus wrong line with #32, instead of regular #1:
- Replace the line number with the usual one */
+ // Bogus wrong line with #32, instead of regular #1: Replace the line
+ // number with the usual one.
hash_buffer(hash, p, q - p);
q += 1;
q[0] = '#';
q++;
}
if (q < end && *q == '\n') {
- /* A newline before the quotation mark -> no match. */
+ // A newline before the quotation mark -> no match.
continue;
}
q++;
free(data);
return false;
}
- /* q points to the beginning of an include file path */
+ // q points to the beginning of an include file path
hash_buffer(hash, p, q - p);
p = q;
while (q < end && *q != '"') {
q++;
}
- /* p and q span the include file path */
- path = x_strndup(p, q - p);
- path = make_relative_path(path);
- hash_string(hash, path);
- remember_include_file(path, hash);
+ // Look for preprocessor flags, after the "filename".
+ bool system = false;
+ char *r = q + 1;
+ while (r < end && *r != '\n') {
+ if (*r == '3') { // System header.
+ system = true;
+ }
+ r++;
+ }
+ // p and q span the include file path.
+ char *inc_path = x_strndup(p, q - p);
+ if (!has_absolute_include_headers) {
+ has_absolute_include_headers = is_absolute_path(inc_path);
+ }
+ inc_path = make_relative_path(inc_path);
+ remember_include_file(inc_path, hash, system);
p = q;
} else {
q++;
hash_buffer(hash, p, (end - p));
free(data);
- /* Explicitly check the .gch/.pch/.pth file, Clang does not include any
- * mention of it in the preprocessed output. */
+ // Explicitly check the .gch/.pch/.pth file, Clang does not include any
+ // mention of it in the preprocessed output.
if (included_pch_file) {
char *path = x_strdup(included_pch_file);
path = make_relative_path(path);
hash_string(hash, path);
- remember_include_file(path, hash);
+ remember_include_file(path, hash, false);
}
return true;
}
-/* Copy or link a file to the cache. */
+// Replace absolute paths with relative paths in the provided dependency file.
static void
-put_file_in_cache(const char *source, const char *dest)
+use_relative_paths_in_depfile(const char *depfile)
{
- int ret;
- struct stat st;
- bool do_link = conf->hard_link && !conf->compression;
+ if (str_eq(conf->base_dir, "")) {
+ cc_log("Base dir not set, skip using relative paths");
+ return; // nothing to do
+ }
+ if (!has_absolute_include_headers) {
+ cc_log("No absolute path for included files found, skip using relative"
+ " paths");
+ return; // nothing to do
+ }
+
+ FILE *f;
+ f = fopen(depfile, "r");
+ if (!f) {
+ cc_log("Cannot open dependency file: %s (%s)", depfile, strerror(errno));
+ return;
+ }
+
+ char *tmp_file = format("%s.tmp", depfile);
+ FILE *tmpf = create_tmp_file(&tmp_file, "w");
+
+ bool result = false;
+ char buf[10000];
+ while (fgets(buf, sizeof(buf), f) && !ferror(tmpf)) {
+ char *saveptr;
+ char *token = strtok_r(buf, " \t", &saveptr);
+ while (token) {
+ char *relpath;
+ if (is_absolute_path(token) && str_startswith(token, conf->base_dir)) {
+ relpath = make_relative_path(x_strdup(token));
+ result = true;
+ } else {
+ relpath = token;
+ }
+ if (token != buf) { // This is a dependency file.
+ fputc(' ', tmpf);
+ }
+ fputs(relpath, tmpf);
+ if (relpath != token) {
+ free(relpath);
+ }
+ token = strtok_r(NULL, " \t", &saveptr);
+ }
+ }
+
+ if (ferror(f)) {
+ cc_log("Error reading dependency file: %s, skip relative path usage",
+ depfile);
+ result = false;
+ goto out;
+ }
+ if (ferror(tmpf)) {
+ cc_log("Error writing temporary dependency file: %s, skip relative path"
+ " usage", tmp_file);
+ result = false;
+ goto out;
+ }
+
+out:
+ fclose(tmpf);
+ fclose(f);
+ if (result) {
+ if (x_rename(tmp_file, depfile) != 0) {
+ cc_log("Error renaming dependency file: %s -> %s (%s), skip relative"
+ " path usage", tmp_file, depfile, strerror(errno));
+ result = false;
+ } else {
+ cc_log("Renamed dependency file: %s -> %s", tmp_file, depfile);
+ }
+ }
+ if (!result) {
+ cc_log("Removing temporary dependency file: %s", tmp_file);
+ x_unlink(tmp_file);
+ }
+ free(tmp_file);
+}
+// Copy or link a file to the cache.
+static void
+put_file_in_cache(const char *source, const char *dest)
+{
assert(!conf->read_only);
assert(!conf->read_only_direct);
+ bool do_link = conf->hard_link && !conf->compression;
if (do_link) {
x_unlink(dest);
- ret = link(source, dest);
- } else {
- ret = copy_file(
- source, dest, conf->compression ? conf->compression_level : 0);
+ int ret = link(source, dest);
+ if (ret != 0) {
+ cc_log("Failed to link %s to %s: %s", source, dest, strerror(errno));
+ cc_log("Falling back to copying");
+ do_link = false;
+ }
}
- if (ret != 0) {
- cc_log("Failed to %s %s to %s: %s",
- do_link ? "link" : "copy",
- source,
- dest,
- strerror(errno));
- stats_update(STATS_ERROR);
- failed();
+ if (!do_link) {
+ int ret = copy_file(
+ source, dest, conf->compression ? conf->compression_level : 0);
+ if (ret != 0) {
+ cc_log("Failed to copy %s to %s: %s", source, dest, strerror(errno));
+ stats_update(STATS_ERROR);
+ failed();
+ }
}
+
cc_log("Stored in cache: %s -> %s", source, dest);
+
+ struct stat st;
if (x_stat(dest, &st) != 0) {
stats_update(STATS_ERROR);
failed();
stats_update_size(file_size(&st), 1);
}
-/* Copy or link a file from the cache. */
+// Copy or link a file from the cache.
static void
get_file_from_cache(const char *source, const char *dest)
{
int ret;
bool do_link = conf->hard_link && !file_is_compressed(source);
-
if (do_link) {
x_unlink(dest);
ret = link(source, dest);
if (ret == -1) {
if (errno == ENOENT || errno == ESTALE) {
- /* Someone removed the file just before we began copying? */
+ // Someone removed the file just before we began copying?
cc_log("Cache file %s just disappeared from cache", source);
stats_update(STATS_MISSING);
} else {
stats_update(STATS_ERROR);
}
- /* If there was trouble getting a file from the cached result, wipe the
- * whole cached result for consistency. */
+ // 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);
cc_log("Created from cache: %s -> %s", source, dest);
}
-/* Send cached stderr, if any, to stderr. */
+// Send cached stderr, if any, to stderr.
static void
send_cached_stderr(void)
{
}
}
-/* Create or update the manifest file. */
+// 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
return;
}
+ struct stat st;
+ size_t old_size = 0; // in bytes
if (stat(manifest_path, &st) == 0) {
old_size = file_size(&st);
}
}
}
-/* run the real compiler and put the result in cache */
+// Run the real compiler and put the result in cache.
static void
to_cache(struct args *args)
{
- char *tmp_stdout, *tmp_stderr, *tmp_cov;
- char *tmp_dwo = NULL;
- struct stat st;
- int status, tmp_stdout_fd, tmp_stderr_fd;
-
- 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);
+ char *tmp_stdout = format("%s.tmp.stdout", cached_obj);
+ int tmp_stdout_fd = create_tmp_fd(&tmp_stdout);
+ char *tmp_stderr = format("%s.tmp.stderr", cached_obj);
+ int tmp_stderr_fd = create_tmp_fd(&tmp_stderr);
+ char *tmp_cov;
if (generating_coverage) {
char *tmp_aux;
- /* gcc has some funny rule about max extension length */
+ // GCC has some funny rule about max extension length.
if (strlen(get_extension(output_obj)) < 6) {
tmp_aux = remove_extension(output_obj);
} else {
tmp_cov = NULL;
}
- /* GCC (at least 4.8 and 4.9) forms the .dwo file name by removing everything
- * after (and including) the last "." from the object file name and then
- * appending ".dwo".
- */
+ // GCC (at least 4.8 and 4.9) forms the .dwo file name by removing everything
+ // after (and including) the last "." from the object file name and then
+ // appending ".dwo".
+ char *tmp_dwo = NULL;
if (using_split_dwarf) {
char *base_name = remove_extension(output_obj);
tmp_dwo = format("%s.dwo", base_name);
args_add(args, output_dia);
}
- /* Turn off DEPENDENCIES_OUTPUT when running cc1, because
- * otherwise it will emit a line like
- *
- * tmp.stdout.vexed.732.o: /home/mbp/.ccache/tmp.stdout.vexed.732.i
- */
+ // Turn off DEPENDENCIES_OUTPUT when running cc1, because otherwise it will
+ // emit a line like this:
+ //
+ // tmp.stdout.vexed.732.o: /home/mbp/.ccache/tmp.stdout.vexed.732.i
x_unsetenv("DEPENDENCIES_OUTPUT");
if (conf->run_second_cpp) {
}
cc_log("Running real compiler");
- status = execute(args->argv, tmp_stdout_fd, tmp_stderr_fd, &compiler_pid);
+ int status =
+ execute(args->argv, tmp_stdout_fd, tmp_stderr_fd, &compiler_pid);
args_pop(args, 3);
+ struct stat st;
if (x_stat(tmp_stdout, &st) != 0) {
- /* The stdout file was removed - cleanup in progress? Better bail out. */
+ // The stdout file was removed - cleanup in progress? Better bail out.
stats_update(STATS_MISSING);
tmp_unlink(tmp_stdout);
tmp_unlink(tmp_stderr);
}
tmp_unlink(tmp_stdout);
- /*
- * Merge stderr from the preprocessor (if any) and stderr from the real
- * compiler into tmp_stderr.
- */
+ // Merge stderr from the preprocessor (if any) and stderr from the real
+ // compiler into tmp_stderr.
if (cpp_stderr) {
- int fd_cpp_stderr;
- int fd_real_stderr;
- int fd_result;
- char *tmp_stderr2;
-
- tmp_stderr2 = format("%s.2", tmp_stderr);
+ char *tmp_stderr2 = format("%s.2", tmp_stderr);
if (x_rename(tmp_stderr, tmp_stderr2)) {
cc_log("Failed to rename %s to %s: %s", tmp_stderr, tmp_stderr2,
strerror(errno));
failed();
}
- fd_cpp_stderr = open(cpp_stderr, O_RDONLY | O_BINARY);
+
+ int fd_cpp_stderr = open(cpp_stderr, O_RDONLY | O_BINARY);
if (fd_cpp_stderr == -1) {
cc_log("Failed opening %s: %s", cpp_stderr, strerror(errno));
failed();
}
- fd_real_stderr = open(tmp_stderr2, O_RDONLY | O_BINARY);
+
+ int fd_real_stderr = open(tmp_stderr2, O_RDONLY | O_BINARY);
if (fd_real_stderr == -1) {
cc_log("Failed opening %s: %s", tmp_stderr2, strerror(errno));
failed();
}
- fd_result = open(tmp_stderr, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+
+ int fd_result =
+ open(tmp_stderr, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
if (fd_result == -1) {
cc_log("Failed opening %s: %s", tmp_stderr, strerror(errno));
failed();
}
+
copy_fd(fd_cpp_stderr, fd_result);
copy_fd(fd_real_stderr, fd_result);
close(fd_cpp_stderr);
}
if (status != 0) {
- int fd;
cc_log("Compiler gave exit status %d", status);
stats_update(STATS_STATUS);
- fd = open(tmp_stderr, O_RDONLY | O_BINARY);
+ int fd = open(tmp_stderr, O_RDONLY | O_BINARY);
if (fd != -1) {
- /* We can output stderr immediately instead of rerunning the compiler. */
+ // We can output stderr immediately instead of rerunning the compiler.
copy_fd(fd, 2);
close(fd);
tmp_unlink(tmp_stderr);
}
cc_log("Stored in cache: %s", cached_stderr);
if (!conf->compression
- /* If the file was compressed, obtain the size again: */
+ // If the file was compressed, obtain the size again:
|| x_stat(cached_stderr, &st) == 0) {
stats_update_size(file_size(&st), 1);
}
} else {
tmp_unlink(tmp_stderr);
if (conf->recache) {
- /* If recaching, we need to remove any previous .stderr. */
+ // If recaching, we need to remove any previous .stderr.
x_unlink(cached_stderr);
}
}
if (generating_coverage) {
- /* gcc won't generate notes if there is no code */
+ // GCC won't generate notes if there is no code.
if (stat(tmp_cov, &st) != 0 && errno == ENOENT) {
FILE *f = fopen(cached_cov, "wb");
cc_log("Creating placeholder: %s", cached_cov);
}
if (generating_dependencies) {
+ use_relative_paths_in_depfile(output_dep);
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
- * be done almost anywhere, but we might as well do it near the end as we
- * save the stat call if we exit early.
- */
+ // Make sure we have a CACHEDIR.TAG in the cache part of cache_dir. This can
+ // be done almost anywhere, but we might as well do it near the end as we
+ // save the stat call if we exit early.
{
char *first_level_dir = dirname(stats_file);
if (create_cachedirtag(first_level_dir) != 0) {
}
free(first_level_dir);
- /* Remove any CACHEDIR.TAG on the cache_dir level where it was located in
- * previous ccache versions. */
+ // Remove any CACHEDIR.TAG on the cache_dir level where it was located in
+ // previous ccache versions.
if (getpid() % 1000 == 0) {
char *path = format("%s/CACHEDIR.TAG", conf->cache_dir);
x_unlink(path);
}
}
- /* Everything OK. */
+ // Everything OK.
send_cached_stderr();
update_manifest_file();
free(tmp_dwo);
}
-/*
- * Find the object file name by running the compiler in preprocessor mode.
- * Returns the hash as a heap-allocated hex string.
- */
+// Find the object file name by running the compiler in preprocessor mode.
+// Returns the hash as a heap-allocated hex string.
static struct file_hash *
get_object_name_from_cpp(struct args *args, struct mdfour *hash)
{
- char *input_base;
- char *tmp;
- char *path_stdout, *path_stderr;
- int status, path_stderr_fd;
- struct file_hash *result;
-
- /* ~/hello.c -> tmp.hello.123.i
- * limit the basename to 10
- * characters in order to cope with filesystem with small
- * maximum filename length limits */
- input_base = basename(input_file);
- tmp = strchr(input_base, '.');
- if (tmp) {
- *tmp = 0;
- }
- if (strlen(input_base) > 10) {
- input_base[10] = 0;
- }
-
- path_stderr = format("%s/tmp.cpp_stderr", temp_dir());
- path_stderr_fd = create_tmp_fd(&path_stderr);
- add_pending_tmp_file(path_stderr);
-
time_of_compilation = time(NULL);
+ char *path_stderr = format("%s/tmp.cpp_stderr", temp_dir());
+ int path_stderr_fd = create_tmp_fd(&path_stderr);
+ add_pending_tmp_file(path_stderr);
+
+ char *path_stdout;
+ int status;
if (direct_i_file) {
- /* We are compiling a .i or .ii file - that means we can skip the cpp stage
- * and directly form the correct i_tmpfile. */
+ // We are compiling a .i or .ii file - that means we can skip the cpp stage
+ // and directly form the correct i_tmpfile.
path_stdout = input_file;
status = 0;
} else {
- /* Run cpp on the input file to obtain the .i. */
- int path_stdout_fd;
+ // Run cpp on the input file to obtain the .i.
+
+ // Limit the basename to 10 characters in order to cope with filesystem with
+ // small maximum filename length limits.
+ char *input_base = basename(input_file);
+ char *tmp = strchr(input_base, '.');
+ if (tmp) {
+ *tmp = 0;
+ }
+ if (strlen(input_base) > 10) {
+ input_base[10] = 0;
+ }
+
path_stdout = format("%s/%s.stdout", temp_dir(), input_base);
- path_stdout_fd = create_tmp_fd(&path_stdout);
+ int path_stdout_fd = create_tmp_fd(&path_stdout);
add_pending_tmp_file(path_stdout);
+ int args_added = 2;
args_add(args, "-E");
+ if (conf->keep_comments_cpp) {
+ args_add(args, "-C");
+ args_added = 3;
+ }
args_add(args, input_file);
+ add_prefix(args, conf->prefix_command_cpp);
cc_log("Running preprocessor");
status = execute(args->argv, path_stdout_fd, path_stderr_fd, &compiler_pid);
- args_pop(args, 2);
+ args_pop(args, args_added);
}
if (status != 0) {
}
if (conf->unify) {
- /* When we are doing the unifying tricks we need to include the input file
- * name in the hash to get the warnings right. */
+ // When we are doing the unifying tricks we need to include the input file
+ // name in the hash to get the warnings right.
hash_delimiter(hash, "unifyfilename");
hash_string(hash, input_file);
if (direct_i_file) {
i_tmpfile = input_file;
} else {
- /* i_tmpfile needs the proper cpp_extension for the compiler to do its
- * thing correctly. */
+ // i_tmpfile needs the proper cpp_extension for the compiler to do its
+ // thing correctly
i_tmpfile = format("%s.%s", path_stdout, conf->cpp_extension);
x_rename(path_stdout, i_tmpfile);
add_pending_tmp_file(i_tmpfile);
if (conf->run_second_cpp) {
free(path_stderr);
} else {
- /*
- * If we are using the CPP trick, we need to remember this
- * stderr data and output it just before the main stderr from
- * the compiler pass.
- */
+ // If we are using the CPP trick, we need to remember this stderr data and
+ // output it just before the main stderr from the compiler pass.
cpp_stderr = path_stderr;
hash_delimiter(hash, "runsecondcpp");
hash_string(hash, "false");
}
- result = x_malloc(sizeof(*result));
+ struct file_hash *result = x_malloc(sizeof(*result));
hash_result_as_bytes(hash, result->hash);
result->size = hash->totalN;
return result;
static void
update_cached_result_globals(struct file_hash *hash)
{
- char *object_name;
- object_name = format_hash_as_string(hash->hash, hash->size);
+ char *object_name = format_hash_as_string(hash->hash, hash->size);
cached_obj_hash = hash;
cached_obj = get_path_in_cache(object_name, ".o");
cached_stderr = get_path_in_cache(object_name, ".stderr");
free(object_name);
}
-/*
- * Hash mtime or content of a file, or the output of a command, according to
- * the CCACHE_COMPILERCHECK setting.
- */
+// Hash mtime or content of a file, or the output of a command, according to
+// the CCACHE_COMPILERCHECK setting.
static void
hash_compiler(struct mdfour *hash, struct stat *st, const char *path,
bool allow_command)
{
if (str_eq(conf->compiler_check, "none")) {
- /* Do nothing. */
+ // Do nothing.
} else if (str_eq(conf->compiler_check, "mtime")) {
hash_delimiter(hash, "cc_mtime");
hash_int(hash, st->st_size);
} else if (str_eq(conf->compiler_check, "content") || !allow_command) {
hash_delimiter(hash, "cc_content");
hash_file(hash, path);
- } else { /* command string */
+ } else { // command string
if (!hash_multicommand_output(
hash, conf->compiler_check, orig_args->argv[0])) {
fatal("Failure running compiler check command: %s", conf->compiler_check);
}
}
-/*
- * Note that these compiler checks are unreliable, so nothing should
- * hard-depend on them.
- */
+// Note that these compiler checks are unreliable, so nothing should
+// hard-depend on them.
static bool
compiler_is_clang(struct args *args)
{
char *name = basename(args->argv[0]);
- bool is = strstr(name, "clang") != NULL;
+ bool result = strstr(name, "clang") != NULL;
free(name);
- return is;
+ return result;
}
static bool
compiler_is_gcc(struct args *args)
{
char *name = basename(args->argv[0]);
- bool is = strstr(name, "gcc") || strstr(name, "g++");
+ bool result = strstr(name, "gcc") || strstr(name, "g++");
free(name);
- return is;
+ return result;
}
-/*
- * Update a hash sum with information common for the direct and preprocessor
- * modes.
- */
+// Update a hash sum with information common for the direct and preprocessor
+// modes.
static void
calculate_common_hash(struct args *args, struct mdfour *hash)
{
- struct stat st;
- char *p;
- const char *full_path;
-#ifdef _WIN32
- const char *ext;
- char full_path_win_ext[MAX_PATH + 1] = {0};
-#endif
-
hash_string(hash, HASH_PREFIX);
- /*
- * We have to hash the extension, as a .i file isn't treated the same
- * by the compiler as a .ii file.
- */
+ // We have to hash the extension, as a .i file isn't treated the same by the
+ // compiler as a .ii file.
hash_delimiter(hash, "ext");
hash_string(hash, conf->cpp_extension);
#ifdef _WIN32
- ext = strrchr(args->argv[0], '.');
+ const char *ext = strrchr(args->argv[0], '.');
+ char full_path_win_ext[MAX_PATH + 1] = {0};
add_exe_ext_if_no_to_fullpath(full_path_win_ext, MAX_PATH, ext,
args->argv[0]);
- full_path = full_path_win_ext;
+ const char *full_path = full_path_win_ext;
#else
- full_path = args->argv[0];
+ const char *full_path = args->argv[0];
#endif
+ struct stat st;
if (x_stat(full_path, &st) != 0) {
stats_update(STATS_COMPILER);
failed();
}
- /*
- * Hash information about the compiler.
- */
+ // Hash information about the compiler.
hash_compiler(hash, &st, args->argv[0], true);
- /*
- * Also hash the compiler name as some compilers use hard links and
- * behave differently depending on the real name.
- */
+ // Also hash the compiler name as some compilers use hard links and behave
+ // differently depending on the real name.
hash_delimiter(hash, "cc_name");
- p = basename(args->argv[0]);
+ char *p = basename(args->argv[0]);
hash_string(hash, p);
free(p);
- /* Possibly hash the current working directory. */
- if (conf->hash_dir) {
+ // Possibly hash the current working directory.
+ if (generating_debuginfo && conf->hash_dir) {
char *cwd = gnu_getcwd();
+ if (debug_prefix_map) {
+ char *map = debug_prefix_map;
+ char *sep = strchr(map, '=');
+ if (sep) {
+ char *old = x_strndup(map, sep - map);
+ char *new = x_strdup(sep + 1);
+ cc_log("Relocating debuginfo cwd %s, from %s to %s", cwd, old, new);
+ if (str_startswith(cwd, old)) {
+ char *dir = format("%s%s", new, cwd + strlen(old));
+ free(cwd);
+ cwd = dir;
+ }
+ free(old);
+ free(new);
+ }
+ }
if (cwd) {
hash_delimiter(hash, "cwd");
hash_string(hash, cwd);
}
}
- /* Possibly hash the coverage data file path. */
+ // Possibly hash the coverage data file path.
if (generating_coverage && profile_arcs) {
char *dir = dirname(output_obj);
if (profile_dir) {
dir = real_dir;
}
if (dir) {
- char *gcda_path;
char *base_name = basename(output_obj);
p = remove_extension(base_name);
free(base_name);
- gcda_path = format("%s/%s.gcda", dir, p);
+ char *gcda_path = format("%s/%s.gcda", dir, p);
cc_log("Hashing coverage path %s", gcda_path);
free(p);
hash_delimiter(hash, "gcda");
}
if (!str_eq(conf->extra_files_to_hash, "")) {
- char *path, *p, *q, *saveptr = NULL;
- p = x_strdup(conf->extra_files_to_hash);
- q = p;
+ char *p = x_strdup(conf->extra_files_to_hash);
+ char *q = p;
+ char *path;
+ char *saveptr = NULL;
while ((path = strtok_r(q, PATH_DELIM, &saveptr))) {
cc_log("Hashing extra file %s", path);
hash_delimiter(hash, "extrafile");
free(p);
}
- /* Possibly hash GCC_COLORS (for color diagnostics). */
+ // Possibly hash GCC_COLORS (for color diagnostics).
if (compiler_is_gcc(args)) {
const char *gcc_colors = getenv("GCC_COLORS");
if (gcc_colors) {
}
}
-/*
- * Update a hash sum with information specific to the direct and preprocessor
- * modes and calculate the object hash. Returns the object hash on success,
- * otherwise NULL. Caller frees.
- */
+// Update a hash sum with information specific to the direct and preprocessor
+// 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 mdfour *hash, int direct_mode)
{
- int i;
- struct stat st;
- struct file_hash *object_hash = NULL;
- char *p;
-
if (direct_mode) {
hash_delimiter(hash, "manifest version");
hash_int(hash, MANIFEST_VERSION);
}
- /* first the arguments */
- for (i = 1; i < args->argc; i++) {
- /* -L doesn't affect compilation. */
+ // First the arguments.
+ for (int i = 1; i < args->argc; i++) {
+ // -L doesn't affect compilation.
if (i < args->argc-1 && str_eq(args->argv[i], "-L")) {
i++;
continue;
continue;
}
- /* -Wl,... doesn't affect compilation. */
+ // -Wl,... doesn't affect compilation.
if (str_startswith(args->argv[i], "-Wl,")) {
continue;
}
- /* The -fdebug-prefix-map option may be used in combination with
- * CCACHE_BASEDIR to reuse results across different directories. Skip it
- * from hashing. */
+ // The -fdebug-prefix-map option may be used in combination with
+ // CCACHE_BASEDIR to reuse results across different directories. Skip it
+ // from hashing.
if (str_startswith(args->argv[i], "-fdebug-prefix-map=")) {
continue;
}
- /* When using the preprocessor, some arguments don't contribute
- * to the hash. The theory is that these arguments will change
- * the output of -E if they are going to have any effect at
- * all. For precompiled headers this might not be the case. */
+ // When using the preprocessor, some arguments don't contribute to the
+ // hash. The theory is that these arguments will change the output of -E if
+ // they are going to have any effect at all. For precompiled headers this
+ // might not be the case.
if (!direct_mode && !output_is_precompiled_header
&& !using_precompiled_header) {
if (compopt_affects_cpp(args->argv[i])) {
}
}
- /* If we're generating dependencies, we make sure to skip the
- * filename of the dependency file, since it doesn't impact the
- * output.
- */
+ // If we're generating dependencies, we make sure to skip the filename of
+ // the dependency file, since it doesn't impact the output.
if (generating_dependencies) {
if (str_startswith(args->argv[i], "-Wp,")) {
if (str_startswith(args->argv[i], "-Wp,-MD,")
continue;
}
} else if (str_startswith(args->argv[i], "-MF")) {
- bool separate_argument = (strlen(args->argv[i]) == 3);
-
- /* In either case, hash the "-MF" part. */
+ // In either case, hash the "-MF" part.
hash_string_length(hash, args->argv[i], 3);
+ bool separate_argument = (strlen(args->argv[i]) == 3);
if (separate_argument) {
- /* Next argument is dependency name, so
- * skip it. */
+ // Next argument is dependency name, so skip it.
i++;
}
continue;
}
}
- p = NULL;
+ char *p = NULL;
if (str_startswith(args->argv[i], "-specs=")) {
p = args->argv[i] + 7;
} else if (str_startswith(args->argv[i], "--specs=")) {
p = args->argv[i] + 8;
}
+
+ struct stat st;
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. */
+ // 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");
hash_compiler(hash, &st, p, false);
continue;
continue;
}
- /* All other arguments are included in the hash. */
+ // All other arguments are included in the hash.
hash_delimiter(hash, "arg");
hash_string(hash, args->argv[i]);
if (i + 1 < args->argc && compopt_takes_arg(args->argv[i])) {
}
}
- /*
- * For profile generation (-fprofile-arcs, -fprofile-generate):
- * - hash profile directory
- * - output to the real file first
- *
- * For profile usage (-fprofile-use):
- * - hash profile data
- *
- * -fbranch-probabilities and -fvpt usage is covered by
- * -fprofile-generate/-fprofile-use.
- *
- * The profile directory can be specified as an argument to
- * -fprofile-generate=, -fprofile-use=, or -fprofile-dir=.
- */
-
- /*
- * We need to output to the real object first here, otherwise runtime
- * artifacts will be produced in the wrong place.
- */
+ // For profile generation (-fprofile-arcs, -fprofile-generate):
+ // - hash profile directory
+ //
+ // For profile usage (-fprofile-use):
+ // - hash profile data
+ //
+ // -fbranch-probabilities and -fvpt usage is covered by
+ // -fprofile-generate/-fprofile-use.
+ //
+ // The profile directory can be specified as an argument to
+ // -fprofile-generate=, -fprofile-use= or -fprofile-dir=.
if (profile_generate) {
if (!profile_dir) {
profile_dir = get_cwd();
}
if (profile_use) {
- /* Calculate gcda name */
- char *gcda_name;
- char *base_name;
- base_name = remove_extension(output_obj);
+ // Calculate gcda name.
if (!profile_dir) {
profile_dir = get_cwd();
}
- gcda_name = format("%s/%s.gcda", profile_dir, base_name);
+ char *base_name = remove_extension(output_obj);
+ char *gcda_name = format("%s/%s.gcda", profile_dir, base_name);
cc_log("Adding profile data %s to our hash", gcda_name);
- /* Add the gcda to our hash */
+ // Add the gcda to our hash.
hash_delimiter(hash, "-fprofile-use");
hash_file(hash, gcda_name);
free(base_name);
free(gcda_name);
}
+ struct file_hash *object_hash = NULL;
if (direct_mode) {
- char *manifest_name;
- int result;
-
- /* Hash environment variables that affect the preprocessor output. */
- const char **p;
+ // Hash environment variables that affect the preprocessor output.
const char *envvars[] = {
"CPATH",
"C_INCLUDE_PATH",
"CPLUS_INCLUDE_PATH",
"OBJC_INCLUDE_PATH",
- "OBJCPLUS_INCLUDE_PATH", /* clang */
+ "OBJCPLUS_INCLUDE_PATH", // clang
NULL
};
- for (p = envvars; *p; ++p) {
+ for (const char **p = envvars; *p; ++p) {
char *v = getenv(*p);
if (v) {
hash_delimiter(hash, *p);
}
if (!(conf->sloppiness & SLOPPY_FILE_MACRO)) {
- /*
- * The source code file or an include file may contain
- * __FILE__, so make sure that the hash is unique for
- * the file name.
- */
+ // The source code file or an include file may contain __FILE__, so make
+ // sure that the hash is unique for the file name.
hash_delimiter(hash, "inputfile");
hash_string(hash, input_file);
}
hash_delimiter(hash, "sourcecode");
- result = hash_source_code_file(conf, hash, input_file);
+ int result = hash_source_code_file(conf, hash, input_file);
if (result & HASH_SOURCE_CODE_ERROR) {
failed();
}
conf->direct_mode = false;
return NULL;
}
- manifest_name = hash_result(hash);
+ char *manifest_name = hash_result(hash);
manifest_path = get_path_in_cache(manifest_name, ".manifest");
free(manifest_name);
cc_log("Looking for object file hash in %s", manifest_path);
cc_log("Did not find object file hash in manifest");
}
} else {
- object_hash = get_object_name_from_cpp(args, hash);
- cc_log("Got object file hash from preprocessor");
+ if (arch_args_size == 0) {
+ object_hash = get_object_name_from_cpp(args, hash);
+ cc_log("Got object file hash from preprocessor");
+ } else {
+ args_add(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);
+ cc_log("Got object file hash from preprocessor with -arch %s",
+ arch_args[i]);
+ if (i != arch_args_size - 1) {
+ free(object_hash);
+ }
+ args_pop(args, 1);
+ }
+ args_pop(args, 1);
+ }
if (generating_dependencies) {
cc_log("Preprocessor created %s", output_dep);
}
return object_hash;
}
-/*
- * Try to return the compile result from cache. If we can return from cache
- * then this function exits with the correct status code, otherwise it returns.
- */
+// Try to return the compile result from cache. If we can return from cache
+// then this function exits with the correct status code, otherwise it returns.
static void
from_cache(enum fromcache_call_mode mode, bool put_object_in_manifest)
{
- struct stat st;
- bool produce_dep_file = false;
-
- /* the user might be disabling cache hits */
+ // The user might be disabling cache hits.
if (conf->recache) {
return;
}
+ struct stat st;
if (stat(cached_obj, &st) != 0) {
cc_log("Object file %s not in cache", cached_obj);
return;
}
- /* Check if the diagnostic file is there. */
+ // Check if the diagnostic file is there.
if (output_dia && stat(cached_dia, &st) != 0) {
cc_log("Diagnostic file %s not in cache", cached_dia);
return;
}
- /*
- * Occasionally, e.g. on hard reset, our cache ends up as just filesystem
- * meta-data with no content. Catch an easy case of this.
- */
+ // Occasionally, e.g. on hard reset, our cache ends up as just filesystem
+ // 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);
x_unlink(cached_obj);
if (st.st_size == 0) {
cc_log("Invalid (empty) dwo file %s in cache", cached_dwo);
x_unlink(cached_dwo);
- x_unlink(cached_obj); /* to really invalidate */
+ x_unlink(cached_obj); // To really invalidate.
return;
}
}
- /*
- * (If mode != FROMCACHE_DIRECT_MODE, the dependency file is created by
- * gcc.)
- */
- produce_dep_file = generating_dependencies && mode == FROMCACHE_DIRECT_MODE;
+ // (If mode != FROMCACHE_DIRECT_MODE, the dependency file is created by gcc.)
+ bool produce_dep_file =
+ generating_dependencies && mode == FROMCACHE_DIRECT_MODE;
- /* If the dependency file should be in the cache, check that it is. */
+ // If the dependency file should be in the cache, check that it is.
if (produce_dep_file && stat(cached_dep, &st) != 0) {
cc_log("Dependency file %s missing in cache", cached_dep);
return;
}
- /*
- * Copy object file from cache. Do so also for FissionDwarf file, cached_dwo,
- * when -gsplit-dwarf is specified.
- */
+ // Copy object file from cache. Do so also for FissionDwarf file, cached_dwo,
+ // when -gsplit-dwarf is specified.
if (!str_eq(output_obj, "/dev/null")) {
get_file_from_cache(cached_obj, output_obj);
if (using_split_dwarf) {
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 */
+ // The compiler 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);
}
- /* Update modification timestamps to save files from LRU cleanup.
- * Also gives files a sensible mtime when hard-linking. */
+ // Update modification timestamps to save files from LRU cleanup. Also gives
+ // files a sensible mtime when hard-linking.
update_mtime(cached_obj);
update_mtime(cached_stderr);
if (produce_dep_file) {
update_manifest_file();
}
- /* log the cache hit */
+ // Log the cache hit.
switch (mode) {
case FROMCACHE_DIRECT_MODE:
cc_log("Succeeded getting cached result");
break;
}
- /* and exit with the right status code */
+ // And exit with the right status code.
x_exit(0);
}
-/* find the real compiler. We just search the PATH to find an executable of the
- * same name that isn't a link to ourselves */
+// Find the real compiler. We just search the PATH to find an executable of the
+// same name that isn't a link to ourselves.
static void
find_compiler(char **argv)
{
- char *base;
- char *compiler;
-
- base = basename(argv[0]);
-
- /* we might be being invoked like "ccache gcc -c foo.c" */
+ // We might be being invoked like "ccache gcc -c foo.c".
+ char *base = basename(argv[0]);
if (same_executable_name(base, MYNAME)) {
args_remove_first(orig_args);
free(base);
if (is_full_path(orig_args->argv[0])) {
- /* a full path was given */
+ // A full path was given.
return;
}
base = basename(orig_args->argv[0]);
}
- /* support user override of the compiler */
+ // Support user override of the compiler.
if (!str_eq(conf->compiler, "")) {
base = conf->compiler;
}
- compiler = find_executable(base, MYNAME);
-
- /* can't find the compiler! */
+ char *compiler = find_executable(base, MYNAME);
if (!compiler) {
stats_update(STATS_COMPILER);
fatal("Could not find compiler \"%s\" in PATH", base);
return isatty(STDERR_FILENO) && term_env && strcasecmp(term_env, "DUMB") != 0;
}
-/*
- * Process the compiler options into options suitable for passing to the
- * preprocessor and the real compiler. The preprocessor options don't include
- * -E; this is added later. Returns true on success, otherwise false.
- */
+static bool
+detect_pch(const char *option, const char *arg, bool *found_pch)
+{
+ struct stat st;
+
+ // Try to be smart about detecting precompiled headers.
+ char *pch_file = NULL;
+ if (str_eq(option, "-include-pch") || str_eq(option, "-include-pth")) {
+ if (stat(arg, &st) == 0) {
+ cc_log("Detected use of precompiled header: %s", arg);
+ pch_file = x_strdup(arg);
+ }
+ } else {
+ char *gchpath = format("%s.gch", arg);
+ if (stat(gchpath, &st) == 0) {
+ cc_log("Detected use of precompiled header: %s", gchpath);
+ pch_file = x_strdup(gchpath);
+ } else {
+ char *pchpath = format("%s.pch", arg);
+ if (stat(pchpath, &st) == 0) {
+ cc_log("Detected use of precompiled header: %s", pchpath);
+ pch_file = x_strdup(pchpath);
+ } else {
+ // clang may use pretokenized headers.
+ char *pthpath = format("%s.pth", arg);
+ if (stat(pthpath, &st) == 0) {
+ cc_log("Detected use of pretokenized header: %s", pthpath);
+ pch_file = x_strdup(pthpath);
+ }
+ free(pthpath);
+ }
+ free(pchpath);
+ }
+ free(gchpath);
+ }
+
+ if (pch_file) {
+ if (included_pch_file) {
+ cc_log("Multiple precompiled headers used: %s and %s\n",
+ included_pch_file, pch_file);
+ stats_update(STATS_ARGS);
+ return false;
+ }
+ included_pch_file = pch_file;
+ *found_pch = true;
+ }
+ return true;
+}
+
+// Process the compiler options into options suitable for passing to the
+// preprocessor and the real compiler. The preprocessor options don't include
+// -E; this is added later. Returns true on success, otherwise false.
bool
cc_process_args(struct args *args, struct args **preprocessor_args,
struct args **compiler_args)
{
- int i;
bool found_c_opt = false;
bool found_S_opt = false;
- bool found_arch_opt = false;
bool found_pch = false;
bool found_fpch_preprocess = false;
- const char *explicit_language = NULL; /* As specified with -x. */
- const char *file_language; /* As deduced from file extension. */
- const char *actual_language; /* Language to actually use. */
+ const char *explicit_language = NULL; // As specified with -x.
+ const char *file_language; // As deduced from file extension.
+ const char *actual_language; // Language to actually use.
const char *input_charset = NULL;
- struct stat st;
- /* is the dependency makefile name overridden with -MF? */
+ // Is the dependency makefile name overridden with -MF?
bool dependency_filename_specified = false;
- /* is the dependency makefile target name specified with -MT or -MQ? */
+ // Is the dependency makefile target name specified with -MT or -MQ?
bool dependency_target_specified = false;
- struct args *expanded_args, *stripped_args, *dep_args, *cpp_args;
- int argc;
- char **argv;
- bool result = true;
- bool found_color_diagnostics = false;
-
- expanded_args = args_copy(args);
- stripped_args = args_init(0, NULL);
- dep_args = args_init(0, NULL);
- cpp_args = args_init(0, NULL);
+ // expanded_args is a copy of the original arguments given to the compiler
+ // but with arguments from @file and similar constructs expanded. It's only
+ // used as a temporary data structure to loop over.
+ struct args *expanded_args = args_copy(args);
+ // stripped_args essentially contains all original arguments except those
+ // that only should be passed to the preprocessor (if run_second_cpp is
+ // false) and except dependency options (like -MD and friends).
+ struct args *stripped_args = args_init(0, NULL);
+ // cpp_args contains arguments that were not added to stripped_args, i.e.
+ // those that should only be passed to the preprocessor if run_second_cpp is
+ // false. If run_second_cpp is true, they will be passed to the compiler as
+ // well.
+ struct args *cpp_args = args_init(0, NULL);
+ // dep_args contains dependency options like -MD. They only passed to the
+ // preprocessor, never to the compiler.
+ struct args *dep_args = args_init(0, NULL);
- argc = expanded_args->argc;
- argv = expanded_args->argv;
+ bool found_color_diagnostics = false;
+ int debug_level = 0;
+ const char *debug_argument = NULL;
+ int argc = expanded_args->argc;
+ char **argv = expanded_args->argv;
args_add(stripped_args, argv[0]);
- for (i = 1; i < argc; i++) {
- /* The user knows best: just swallow the next arg */
+ bool result = true;
+ for (int i = 1; i < argc; i++) {
+ // The user knows best: just swallow the next arg.
if (str_eq(argv[i], "--ccache-skip")) {
i++;
if (i == argc) {
continue;
}
- /* Special case for -E. */
+ // Special case for -E.
if (str_eq(argv[i], "-E")) {
stats_update(STATS_PREPROCESSING);
result = false;
goto out;
}
- /* Handle "@file" argument. */
+ // Handle "@file" argument.
if (str_startswith(argv[i], "@") || str_startswith(argv[i], "-@")) {
char *argpath = argv[i] + 1;
- struct args *file_args;
if (argpath[-1] == '-') {
++argpath;
}
- file_args = args_init_from_gcc_atfile(argpath);
+ struct args *file_args = args_init_from_gcc_atfile(argpath);
if (!file_args) {
cc_log("Couldn't read arg file %s", argpath);
stats_update(STATS_ARGS);
continue;
}
- /* These are always too hard. */
- if (compopt_too_hard(argv[i])
- || str_startswith(argv[i], "-fdump-")) {
+ // Handle cuda "-optf" and "--options-file" argument.
+ if (str_eq(argv[i], "-optf") || str_eq(argv[i], "--options-file")) {
+ if (i > argc) {
+ cc_log("Expected argument after -optf/--options-file");
+ stats_update(STATS_UNSUPPORTED);
+ result = false;
+ goto out;
+ }
+ ++i;
+
+ // Argument is a comma-separated list of files.
+ char *str_start = argv[i];
+ char *str_end = strchr(str_start, ',');
+ int index = i + 1;
+
+ if (!str_end) {
+ str_end = str_start + strlen(str_start);
+ }
+
+ while (str_end) {
+ *str_end = '\0';
+ struct args *file_args = args_init_from_gcc_atfile(str_start);
+ if (!file_args) {
+ cc_log("Couldn't read cuda options file %s", str_start);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+
+ int new_index = file_args->argc + index;
+ args_insert(expanded_args, index, file_args, false);
+ index = new_index;
+ str_start = str_end;
+ str_end = strchr(str_start, ',');
+ }
+
+ argc = expanded_args->argc;
+ argv = expanded_args->argv;
+ continue;
+ }
+
+ // These are always too hard.
+ if (compopt_too_hard(argv[i]) || str_startswith(argv[i], "-fdump-")) {
cc_log("Compiler option %s is unsupported", argv[i]);
stats_update(STATS_UNSUPPORTED);
result = false;
goto out;
}
- /* These are too hard in direct mode. */
- if (conf->direct_mode) {
- if (compopt_too_hard_for_direct_mode(argv[i])) {
- cc_log("Unsupported compiler option for direct mode: %s", argv[i]);
- conf->direct_mode = false;
- }
+ // These are too hard in direct mode.
+ if (conf->direct_mode && compopt_too_hard_for_direct_mode(argv[i])) {
+ cc_log("Unsupported compiler option for direct mode: %s", argv[i]);
+ conf->direct_mode = false;
+ }
+
+ // -Xarch_* options are too hard.
+ if (str_startswith(argv[i], "-Xarch_")) {
+ cc_log("Unsupported compiler option :%s", argv[i]);
+ stats_update(STATS_UNSUPPORTED);
+ result = false;
+ goto out;
}
- /* Multiple -arch options are too hard. */
+ // Handle -arch options.
if (str_eq(argv[i], "-arch")) {
- if (found_arch_opt) {
- cc_log("More than one -arch compiler option is unsupported");
+ if (arch_args_size == MAX_ARCH_ARGS - 1) {
+ cc_log("Too many -arch compiler options; ccache supports at most %d",
+ MAX_ARCH_ARGS);
stats_update(STATS_UNSUPPORTED);
result = false;
goto out;
- } else {
- found_arch_opt = true;
}
+
+ ++i;
+ arch_args[arch_args_size] = x_strdup(argv[i]); // It will leak.
+ ++arch_args_size;
+ if (arch_args_size == 2) {
+ conf->run_second_cpp = true;
+ }
+ continue;
}
if (str_eq(argv[i], "-fpch-preprocess")
found_fpch_preprocess = true;
}
- /* we must have -c */
+ // We must have -c.
if (str_eq(argv[i], "-c")) {
found_c_opt = true;
continue;
}
- /* -S changes the default extension */
+ // -S changes the default extension.
if (str_eq(argv[i], "-S")) {
args_add(stripped_args, argv[i]);
found_S_opt = true;
continue;
}
- /*
- * Special handling for -x: remember the last specified language before the
- * input file and strip all -x options from the arguments.
- */
+ // Special handling for -x: remember the last specified language before the
+ // input file and strip all -x options from the arguments.
if (str_eq(argv[i], "-x")) {
if (i == argc-1) {
cc_log("Missing argument to %s", argv[i]);
continue;
}
- /* we need to work out where the output was meant to go */
+ // We need to work out where the output was meant to go.
if (str_eq(argv[i], "-o")) {
if (i == argc-1) {
cc_log("Missing argument to %s", argv[i]);
continue;
}
- /* alternate form of -o, with no space */
+ // Alternate form of -o with no space.
if (str_startswith(argv[i], "-o")) {
output_obj = make_relative_path(x_strdup(&argv[i][2]));
continue;
args_add(stripped_args, argv[i]);
continue;
}
+ if (str_startswith(argv[i], "-fdebug-prefix-map=")) {
+ debug_prefix_map = x_strdup(argv[i] + 19);
+ args_add(stripped_args, argv[i]);
+ continue;
+ }
- /* Debugging is handled specially, so that we know if we can strip line
- * number info. */
+ // Debugging is handled specially, so that we know if we can strip line
+ // number info.
if (str_startswith(argv[i], "-g")) {
- args_add(stripped_args, argv[i]);
- if (conf->unify && !str_eq(argv[i], "-g0")) {
- cc_log("%s used; disabling unify mode", argv[i]);
- conf->unify = false;
+ const char *pLevel = argv[i] + 2;
+ if (str_startswith(argv[i], "-ggdb")) {
+ pLevel = argv[i] + 5;
+ } else if (str_startswith(argv[i], "-gstabs")) {
+ pLevel = argv[i] + 7;
+ } else if (str_startswith(argv[i], "-gcoff")) {
+ pLevel = argv[i] + 6;
+ } else if (str_startswith(argv[i], "-gxcoff")) {
+ pLevel = argv[i] + 7;
+ } else if (str_startswith(argv[i], "-gvms")) {
+ pLevel = argv[i] + 5;
}
- if (str_eq(argv[i], "-g3")) {
- /*
- * Fix for bug 7190 ("commandline macros (-D)
- * have non-zero lineno when using -g3").
- */
- cc_log("%s used; not compiling preprocessed code", argv[i]);
- conf->run_second_cpp = true;
+
+ // Deduce level from argument, default is 2.
+ int foundlevel = -1;
+ if (pLevel[0] == '\0') {
+ foundlevel = 2;
+ } else if (pLevel[0] >= '0' && pLevel[0] <= '9') {
+ foundlevel = atoi(pLevel);
+ }
+
+ if (foundlevel >= 0) {
+ debug_level = foundlevel;
+ debug_argument = argv[i];
+ continue;
}
- continue;
}
- /* These options require special handling, because they
- * behave differently with gcc -E, when the output
- * file is not specified. */
+ // These options require special handling, because they behave differently
+ // with gcc -E, when the output file is not specified.
if (str_eq(argv[i], "-MD") || str_eq(argv[i], "-MMD")) {
generating_dependencies = true;
args_add(dep_args, argv[i]);
continue;
}
if (str_startswith(argv[i], "-MF")) {
- char *arg;
- bool separate_argument = (strlen(argv[i]) == 3);
dependency_filename_specified = true;
free(output_dep);
+
+ char *arg;
+ bool separate_argument = (strlen(argv[i]) == 3);
if (separate_argument) {
- /* -MF arg */
+ // -MF arg
if (i >= argc - 1) {
cc_log("Missing argument to %s", argv[i]);
stats_update(STATS_ARGS);
arg = argv[i + 1];
i++;
} else {
- /* -MFarg */
+ // -MFarg
arg = &argv[i][3];
}
output_dep = make_relative_path(x_strdup(arg));
- /* Keep the format of the args the same */
+ // Keep the format of the args the same.
if (separate_argument) {
args_add(dep_args, "-MF");
args_add(dep_args, output_dep);
continue;
}
if (str_startswith(argv[i], "-MQ") || str_startswith(argv[i], "-MT")) {
- char *relpath;
dependency_target_specified = true;
+
+ char *relpath;
if (strlen(argv[i]) == 3) {
- /* -MQ arg or -MT arg */
+ // -MQ arg or -MT arg
if (i >= argc - 1) {
cc_log("Missing argument to %s", argv[i]);
stats_update(STATS_ARGS);
free(relpath);
i++;
} else {
- char *arg_opt;
- char *option;
- arg_opt = x_strndup(argv[i], 3);
+ char *arg_opt = x_strndup(argv[i], 3);
relpath = make_relative_path(x_strdup(argv[i] + 3));
- option = format("%s%s", arg_opt, relpath);
+ char *option = format("%s%s", arg_opt, relpath);
args_add(dep_args, option);
free(arg_opt);
free(relpath);
args_add(stripped_args, argv[i]);
continue;
}
- if (str_eq(argv[i], "--coverage") /* = -fprofile-arcs -ftest-coverage */
- || str_eq(argv[i], "-coverage")) { /* Undocumented but still works */
+ if (str_eq(argv[i], "--coverage") // = -fprofile-arcs -ftest-coverage
+ || str_eq(argv[i], "-coverage")) { // Undocumented but still works.
profile_arcs = true;
generating_coverage = true;
args_add(stripped_args, argv[i]);
continue;
}
if (str_startswith(argv[i], "-Wp,")) {
- if (str_eq(argv[i], "-Wp,-P") || strstr(argv[i], ",-P,")) {
- /* -P removes preprocessor information in such a way that the object
- * file from compiling the preprocessed file will not be equal to the
- * object file produced when compiling without ccache. */
+ if (str_eq(argv[i], "-Wp,-P")
+ || strstr(argv[i], ",-P,")
+ || str_endswith(argv[i], ",-P")) {
+ // -P removes preprocessor information in such a way that the object
+ // file from compiling the preprocessed file will not be equal to the
+ // object file produced when compiling without ccache.
cc_log("Too hard option -Wp,-P detected");
stats_update(STATS_UNSUPPORTED);
failed();
output_dep = make_relative_path(x_strdup(argv[i] + 9));
args_add(dep_args, argv[i]);
continue;
- } else if (str_eq(argv[i], "-Wp,-MP")
- || (strlen(argv[i]) > 8
- && str_startswith(argv[i], "-Wp,-M")
- && argv[i][7] == ','
- && (argv[i][6] == 'F'
- || argv[i][6] == 'Q'
- || argv[i][6] == 'T')
- && !strchr(argv[i] + 8, ','))) {
- /* TODO: Make argument to MF/MQ/MT relative. */
- args_add(dep_args, argv[i]);
+ } else if (str_startswith(argv[i], "-Wp,-D")
+ && !strchr(argv[i] + 6, ',')) {
+ // Treat it like -D.
+ args_add(dep_args, argv[i] + 4);
continue;
} else if (conf->direct_mode) {
- /*
- * -Wp, can be used to pass too hard options to
- * the preprocessor. Hence, disable direct
- * mode.
- */
+ // -Wp, can be used to pass too hard options to the preprocessor.
+ // Hence, disable direct mode.
cc_log("Unsupported compiler option for direct mode: %s", argv[i]);
conf->direct_mode = false;
}
-
- /* Any other -Wp,* arguments are only relevant for the preprocessor. */
- args_add(cpp_args, argv[i]);
- continue;
}
if (str_eq(argv[i], "-MP")) {
args_add(dep_args, argv[i]);
continue;
}
- /* Input charset needs to be handled specially. */
+ // Input charset needs to be handled specially.
if (str_startswith(argv[i], "-finput-charset=")) {
input_charset = argv[i];
continue;
}
if (str_startswith(argv[i], "-fprofile-")) {
- const char *arg_profile_dir = strchr(argv[i], '=');
char *arg = x_strdup(argv[i]);
- bool supported_profile_option = false;
-
+ const char *arg_profile_dir = strchr(argv[i], '=');
if (arg_profile_dir) {
- char *option = x_strndup(argv[i], arg_profile_dir - argv[i]);
- char *dir;
-
- /* Convert to absolute path. */
- dir = x_realpath(arg_profile_dir + 1);
+ // Convert to absolute path.
+ char *dir = x_realpath(arg_profile_dir + 1);
if (!dir) {
- /* Directory doesn't exist. */
+ // Directory doesn't exist.
dir = x_strdup(arg_profile_dir + 1);
}
- /* We can get a better hit rate by using the real path here. */
+ // We can get a better hit rate by using the real path here.
free(arg);
+ char *option = x_strndup(argv[i], arg_profile_dir - argv[i]);
arg = format("%s=%s", option, dir);
cc_log("Rewriting %s to %s", argv[i], arg);
free(option);
free(dir);
}
+ bool supported_profile_option = false;
if (str_startswith(argv[i], "-fprofile-generate")
|| str_eq(argv[i], "-fprofile-arcs")) {
profile_generate = true;
args_add(stripped_args, arg);
free(arg);
- /*
- * If the profile directory has already been set, give up... Hard to
- * know what the user means, and what the compiler will do.
- */
+ // If the profile directory has already been set, give up... Hard to
+ // know what the user means, and what the compiler will do.
if (arg_profile_dir && profile_dir) {
cc_log("Profile directory already set; giving up");
result = false;
}
if (str_eq(argv[i], "-fdiagnostics-color=auto")) {
if (color_output_possible()) {
- /* Output is redirected, so color output must be forced. */
+ // Output is redirected, so color output must be forced.
args_add(stripped_args, "-fdiagnostics-color=always");
cc_log("Automatically forcing colors");
} else {
continue;
}
- /*
- * Options taking an argument that we may want to rewrite to relative paths
- * to get better hit rate. A secondary effect is that paths in the standard
- * error output produced by the compiler will be normalized.
- */
+ // Options taking an argument that we may want to rewrite to relative paths
+ // to get better hit rate. A secondary effect is that paths in the standard
+ // error output produced by the compiler will be normalized.
if (compopt_takes_path(argv[i])) {
- char *relpath;
- char *pch_file = NULL;
if (i == argc-1) {
cc_log("Missing argument to %s", argv[i]);
stats_update(STATS_ARGS);
goto out;
}
- relpath = make_relative_path(x_strdup(argv[i+1]));
+ if (!detect_pch(argv[i], argv[i+1], &found_pch)) {
+ result = false;
+ goto out;
+ }
+
+ char *relpath = make_relative_path(x_strdup(argv[i+1]));
if (compopt_affects_cpp(argv[i])) {
args_add(cpp_args, argv[i]);
args_add(cpp_args, relpath);
args_add(stripped_args, argv[i]);
args_add(stripped_args, relpath);
}
-
- /* Try to be smart about detecting precompiled headers */
- if (str_eq(argv[i], "-include-pch")
- || str_eq(argv[i], "-include-pth")) {
- if (stat(argv[i+1], &st) == 0) {
- cc_log("Detected use of precompiled header: %s", argv[i+1]);
- found_pch = true;
- pch_file = x_strdup(argv[i+1]);
- }
- } else {
- char *gchpath = format("%s.gch", argv[i+1]);
- if (stat(gchpath, &st) == 0) {
- cc_log("Detected use of precompiled header: %s", gchpath);
- found_pch = true;
- pch_file = x_strdup(gchpath);
- } else {
- char *pchpath = format("%s.pch", argv[i+1]);
- if (stat(pchpath, &st) == 0) {
- cc_log("Detected use of precompiled header: %s", pchpath);
- found_pch = true;
- pch_file = x_strdup(pchpath);
- } else {
- /* clang may use pretokenized headers */
- char *pthpath = format("%s.pth", argv[i+1]);
- if (stat(pthpath, &st) == 0) {
- cc_log("Detected use of pretokenized header: %s", pthpath);
- found_pch = true;
- pch_file = x_strdup(pthpath);
- }
- free(pthpath);
- }
- free(pchpath);
- }
- free(gchpath);
- }
-
- if (pch_file) {
- if (included_pch_file) {
- cc_log("Multiple precompiled headers used: %s and %s\n",
- included_pch_file, pch_file);
- stats_update(STATS_ARGS);
- result = false;
- goto out;
- }
- included_pch_file = pch_file;
- }
-
free(relpath);
+
i++;
continue;
}
- /* Same as above but options with concatenated argument. */
- if (compopt_short(compopt_takes_path, argv[i])) {
- char *relpath;
- char *option;
- relpath = make_relative_path(x_strdup(argv[i] + 2));
- option = format("-%c%s", argv[i][1], relpath);
-
- if (compopt_short(compopt_affects_cpp, argv[i])) {
- args_add(cpp_args, option);
- } else {
- args_add(stripped_args, option);
+ // Same as above but options with concatenated argument beginning with a
+ // slash.
+ if (argv[i][0] == '-') {
+ char *slash_pos = strchr(argv[i], '/');
+ if (slash_pos) {
+ char *option = x_strndup(argv[i], slash_pos - argv[i]);
+ if (compopt_takes_concat_arg(option) && compopt_takes_path(option)) {
+ char *relpath = make_relative_path(x_strdup(slash_pos));
+ char *new_option = format("%s%s", option, relpath);
+ if (compopt_affects_cpp(option)) {
+ args_add(cpp_args, new_option);
+ } else {
+ args_add(stripped_args, new_option);
+ }
+ free(new_option);
+ free(relpath);
+ free(option);
+ continue;
+ } else {
+ free(option);
+ }
}
-
- free(relpath);
- free(option);
- continue;
}
- /* options that take an argument */
+ // Options that take an argument.
if (compopt_takes_arg(argv[i])) {
if (i == argc-1) {
cc_log("Missing argument to %s", argv[i]);
continue;
}
- /* other options */
+ // Other options.
if (argv[i][0] == '-') {
if (compopt_affects_cpp(argv[i])
|| compopt_prefix_affects_cpp(argv[i])) {
continue;
}
- /* if an argument isn't a plain file then assume its
- * an option, not an input file. This allows us to
- * cope better with unusual compiler options */
+ // If an argument isn't a plain file then assume its an option, not an
+ // input file. This allows us to cope better with unusual compiler options.
+ struct stat st;
if (stat(argv[i], &st) != 0 || !S_ISREG(st.st_mode)) {
cc_log("%s is not a regular file, not considering as input file",
argv[i]);
goto out;
}
- /* The source code file path gets put into the notes */
+ // The source code file path gets put into the notes.
if (generating_coverage) {
input_file = x_strdup(argv[i]);
continue;
}
- lstat(argv[i], &st);
- if (S_ISLNK(st.st_mode)) {
- /* Don't rewrite source file path if it's a symlink since
- make_relative_path resolves symlinks using realpath(3) and this leads
- to potentially choosing incorrect relative header files. See the
- "symlink to source file" test. */
+ if (is_symlink(argv[i])) {
+ // Don't rewrite source file path if it's a symlink since
+ // make_relative_path resolves symlinks using realpath(3) and this leads
+ // to potentially choosing incorrect relative header files. See the
+ // "symlink to source file" test.
input_file = x_strdup(argv[i]);
} else {
- /* Rewrite to relative to increase hit rate. */
+ // Rewrite to relative to increase hit rate.
input_file = make_relative_path(x_strdup(argv[i]));
}
- } /* for */
+ } // for
+
+ if (debug_level > 0) {
+ generating_debuginfo = true;
+ args_add(stripped_args, debug_argument);
+ if (conf->unify) {
+ cc_log("%s used; disabling unify mode", debug_argument);
+ conf->unify = false;
+ }
+ if (debug_level >= 3 && !conf->run_second_cpp) {
+ cc_log("%s used; not compiling preprocessed code", debug_argument);
+ conf->run_second_cpp = true;
+ }
+ }
if (found_S_opt) {
- /* Even if -gsplit-dwarf is given, the .dwo file is not generated when -S
- * is also given.
- */
+ // Even if -gsplit-dwarf is given, the .dwo file is not generated when -S
+ // is also given.
using_split_dwarf = false;
cc_log("Disabling caching of dwarf files since -S is used");
}
goto out;
}
- if (!found_c_opt) {
+ if (!found_c_opt && !found_S_opt) {
if (output_is_precompiled_header) {
args_add(stripped_args, "-c");
} else {
cc_log("No -c option found");
- /* I find that having a separate statistic for autoconf tests is useful,
- * as they are the dominant form of "called for link" in many cases */
+ // I find that having a separate statistic for autoconf tests is useful,
+ // as they are the dominant form of "called for link" in many cases.
if (strstr(input_file, "conftest.")) {
stats_update(STATS_CONFTEST);
} else {
direct_i_file = language_is_preprocessed(actual_language);
- if (output_is_precompiled_header) {
- /* It doesn't work to create the .gch from preprocessed source. */
+ if (output_is_precompiled_header && !conf->run_second_cpp) {
+ // It doesn't work to create the .gch from preprocessed source.
cc_log("Creating precompiled header; not compiling preprocessed code");
conf->run_second_cpp = true;
}
conf->cpp_extension = x_strdup(extension_for_language(p_language) + 1);
}
- /* don't try to second guess the compilers heuristics for stdout handling */
+ // Don't try to second guess the compilers heuristics for stdout handling.
if (output_obj && str_eq(output_obj, "-")) {
stats_update(STATS_OUTSTDOUT);
cc_log("Output file is -");
if (output_is_precompiled_header) {
output_obj = format("%s.gch", input_file);
} else {
- char *p;
output_obj = basename(input_file);
- p = strrchr(output_obj, '.');
+ char *p = strrchr(output_obj, '.');
if (!p || !p[1]) {
cc_log("Badly formed object filename");
stats_update(STATS_ARGS);
}
if (using_split_dwarf) {
- char *p;
- p = strrchr(output_obj, '.');
+ char *p = strrchr(output_obj, '.');
if (!p || !p[1]) {
cc_log("Badly formed object filename");
stats_update(STATS_ARGS);
result = false;
goto out;
}
- {
- char *base_name = remove_extension(output_obj);
- output_dwo = format("%s.dwo", base_name);
- free(base_name);
- }
+
+ char *base_name = remove_extension(output_obj);
+ output_dwo = format("%s.dwo", base_name);
+ free(base_name);
}
- /* cope with -o /dev/null */
+ // Cope with -o /dev/null.
+ struct stat st;
if (!str_eq(output_obj, "/dev/null")
&& stat(output_obj, &st) == 0
&& !S_ISREG(st.st_mode)) {
goto out;
}
- /*
- * Some options shouldn't be passed to the real compiler when it compiles
- * preprocessed code:
- *
- * -finput-charset=XXX (otherwise conversion happens twice)
- * -x XXX (otherwise the wrong language is selected)
- */
+ // Some options shouldn't be passed to the real compiler when it compiles
+ // preprocessed code:
+ //
+ // -finput-charset=XXX (otherwise conversion happens twice)
+ // -x XXX (otherwise the wrong language is selected)
if (input_charset) {
args_add(cpp_args, input_charset);
}
args_add(cpp_args, explicit_language);
}
- /*
- * Since output is redirected, compilers will not color their output by
- * default, so force it explicitly if it would be otherwise done.
- */
+ // Since output is redirected, compilers will not color their output by
+ // default, so force it explicitly if it would be otherwise done.
if (!found_color_diagnostics && color_output_possible()) {
if (compiler_is_clang(args)) {
- args_add(stripped_args, "-fcolor-diagnostics");
- cc_log("Automatically enabling colors");
+ if (!str_eq(actual_language, "assembler")) {
+ args_add(stripped_args, "-fcolor-diagnostics");
+ cc_log("Automatically enabling colors");
+ }
} else if (compiler_is_gcc(args)) {
- /*
- * GCC has it since 4.9, but that'd require detecting what GCC version is
- * used for the actual compile. However it requires also GCC_COLORS to be
- * set (and not empty), so use that for detecting if GCC would use
- * colors.
- */
+ // GCC has it since 4.9, but that'd require detecting what GCC version is
+ // used for the actual compile. However it requires also GCC_COLORS to be
+ // set (and not empty), so use that for detecting if GCC would use
+ // colors.
if (getenv("GCC_COLORS") && getenv("GCC_COLORS")[0] != '\0') {
args_add(stripped_args, "-fdiagnostics-color");
cc_log("Automatically enabling colors");
}
}
- /*
- * Add flags for dependency generation only to the preprocessor command line.
- */
+ // Add flags for dependency generation only to the preprocessor command line.
if (generating_dependencies) {
if (!dependency_filename_specified) {
- char *default_depfile_name;
- char *base_name;
-
- base_name = remove_extension(output_obj);
- default_depfile_name = format("%s.d", base_name);
+ char *base_name = remove_extension(output_obj);
+ char *default_depfile_name = format("%s.d", base_name);
free(base_name);
args_add(dep_args, "-MF");
args_add(dep_args, default_depfile_name);
}
}
if (generating_coverage) {
- char *default_covfile_name;
- char *base_name;
-
- base_name = remove_extension(output_obj);
- default_covfile_name = format("%s.gcno", base_name);
+ char *base_name = remove_extension(output_obj);
+ char *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) {
args_extend(*compiler_args, cpp_args);
- } else {
- if (explicit_language) {
- /*
- * Workaround for a bug in Apple's patched distcc -- it doesn't properly
- * reset the language specified with -x, so if -x is given, we have to
- * specify the preprocessed language explicitly.
- */
- args_add(*compiler_args, "-x");
- args_add(*compiler_args, p_language_for_language(explicit_language));
- }
+ } else if (explicit_language) {
+ // Workaround for a bug in Apple's patched distcc -- it doesn't properly
+ // reset the language specified with -x, so if -x is given, we have to
+ // specify the preprocessed language explicitly.
+ args_add(*compiler_args, "-x");
+ args_add(*compiler_args, p_language_for_language(explicit_language));
}
if (found_c_opt) {
args_add(*compiler_args, "-c");
}
- /*
- * Only pass dependency arguments to the preprocesor since Intel's C++
- * compiler doesn't produce a correct .d file when compiling preprocessed
- * source.
- */
+ for (size_t i = 0; i < arch_args_size; ++i) {
+ args_add(*compiler_args, "-arch");
+ args_add(*compiler_args, arch_args[i]);
+ }
+
+ // Only pass dependency arguments to the preprocesor since Intel's C++
+ // compiler doesn't produce a correct .d file when compiling preprocessed
+ // source.
args_extend(cpp_args, dep_args);
*preprocessor_args = args_copy(stripped_args);
static void
create_initial_config_file(struct conf *conf, const char *path)
{
- unsigned max_files;
- uint64_t max_size;
- char *stats_dir;
- FILE *f;
- struct stat st;
-
if (create_parent_dirs(path) != 0) {
return;
}
- stats_dir = format("%s/0", conf->cache_dir);
+ unsigned max_files;
+ uint64_t max_size;
+ char *stats_dir = format("%s/0", conf->cache_dir);
+ struct stat st;
if (stat(stats_dir, &st) == 0) {
stats_get_obsolete_limits(stats_dir, &max_files, &max_size);
- /* STATS_MAXFILES and STATS_MAXSIZE was stored for each top directory. */
+ // STATS_MAXFILES and STATS_MAXSIZE was stored for each top directory.
max_files *= 16;
max_size *= 16;
} else {
}
free(stats_dir);
- f = fopen(path, "w");
+ FILE *f = fopen(path, "w");
if (!f) {
return;
}
fclose(f);
}
-/*
- * Read config file(s), populate variables, create configuration file in cache
- * directory if missing, etc.
- */
+// Read config file(s), populate variables, create configuration file in cache
+// directory if missing, etc.
static void
initialize(void)
{
- char *errmsg;
- char *p;
- struct stat st;
- bool should_create_initial_config = false;
-
conf_free(conf);
conf = conf_create();
- p = getenv("CCACHE_CONFIGPATH");
+ char *errmsg;
+ struct stat st;
+ char *p = getenv("CCACHE_CONFIGPATH");
if (p) {
primary_config_path = x_strdup(p);
} else {
if (stat(secondary_config_path, &st) == 0) {
fatal("%s", errmsg);
}
- /* Missing config file in SYSCONFDIR is OK. */
+ // Missing config file in SYSCONFDIR is OK.
free(errmsg);
}
primary_config_path = format("%s/ccache.conf", conf->cache_dir);
}
+ bool should_create_initial_config = false;
if (!conf_read(conf, primary_config_path, &errmsg)) {
if (stat(primary_config_path, &st) == 0) {
fatal("%s", errmsg);
}
}
-/* Reset the global state. Used by the test suite. */
+// Reset the global state. Used by the test suite.
void
cc_reset(void)
{
free(primary_config_path); primary_config_path = NULL;
free(secondary_config_path); secondary_config_path = NULL;
free(current_working_dir); current_working_dir = NULL;
+ free(debug_prefix_map); debug_prefix_map = NULL;
free(profile_dir); profile_dir = NULL;
free(included_pch_file); included_pch_file = NULL;
args_free(orig_args); orig_args = NULL;
free(cached_dia); cached_dia = NULL;
free(manifest_path); manifest_path = NULL;
time_of_compilation = 0;
+ for (size_t i = 0; i < ignore_headers_len; i++) {
+ free(ignore_headers[i]);
+ ignore_headers[i] = NULL;
+ }
+ free(ignore_headers); ignore_headers = NULL;
+ ignore_headers_len = 0;
if (included_files) {
hashtable_destroy(included_files, 1); included_files = NULL;
}
+ has_absolute_include_headers = false;
+ generating_debuginfo = false;
generating_dependencies = false;
generating_coverage = false;
profile_arcs = false;
using_split_dwarf = false;
}
-/* Make a copy of stderr that will not be cached, so things like
- * distcc can send networking errors to it. */
+// Make a copy of stderr that will not be cached, so things like distcc can
+// send networking errors to it.
static void
setup_uncached_err(void)
{
- char *buf;
- int uncached_fd;
-
- uncached_fd = dup(2);
+ int uncached_fd = dup(2);
if (uncached_fd == -1) {
cc_log("dup(2) failed: %s", strerror(errno));
failed();
}
- /* leak a pointer to the environment */
- buf = format("UNCACHED_ERR_FD=%d", uncached_fd);
-
+ // Leak a pointer to the environment.
+ char *buf = format("UNCACHED_ERR_FD=%d", uncached_fd);
if (putenv(buf) == -1) {
cc_log("putenv failed: %s", strerror(errno));
failed();
cc_bulklog("Config: (%s) %s", origin, descr);
}
-/* the main ccache driver function */
+// The main ccache driver function.
static void
ccache(int argc, char *argv[])
{
- bool put_object_in_manifest = false;
- struct file_hash *object_hash;
- struct file_hash *object_hash_from_manifest = NULL;
- struct mdfour common_hash;
- struct mdfour direct_hash;
- struct mdfour cpp_hash;
-
- /* Arguments (except -E) to send to the preprocessor. */
- struct args *preprocessor_args;
-
- /* Arguments to send to the real compiler. */
- struct args *compiler_args;
-
+#ifndef _WIN32
set_up_signal_handlers();
+#endif
orig_args = args_init(argc, argv);
conf->direct_mode = false;
}
+ conf->limit_multiple = MIN(MAX(conf->limit_multiple, 0.0), 1.0);
+
+ // Arguments (except -E) to send to the preprocessor.
+ struct args *preprocessor_args;
+ // Arguments to send to the real compiler.
+ struct args *compiler_args;
if (!cc_process_args(orig_args, &preprocessor_args, &compiler_args)) {
failed();
}
cc_log("Object file: %s", output_obj);
+ struct mdfour common_hash;
hash_start(&common_hash);
calculate_common_hash(preprocessor_args, &common_hash);
- /* try to find the hash using the manifest */
- direct_hash = common_hash;
+ // Try to find the hash using the manifest.
+ struct mdfour direct_hash = common_hash;
+ bool put_object_in_manifest = false;
+ struct file_hash *object_hash = NULL;
+ struct file_hash *object_hash_from_manifest = NULL;
if (conf->direct_mode) {
cc_log("Trying direct lookup");
object_hash = calculate_object_hash(preprocessor_args, &direct_hash, 1);
if (object_hash) {
update_cached_result_globals(object_hash);
- /*
- * If we can return from cache at this point then do
- * so.
- */
+ // If we can return from cache at this point then do so.
from_cache(FROMCACHE_DIRECT_MODE, 0);
- /*
- * Wasn't able to return from cache at this point.
- * However, the object was already found in manifest,
- * so don't readd it later.
- */
+ // Wasn't able to return from cache at this point. However, the object
+ // was already found in manifest, so don't readd it later.
put_object_in_manifest = false;
object_hash_from_manifest = object_hash;
} else {
- /* Add object to manifest later. */
+ // Add object to manifest later.
put_object_in_manifest = true;
}
}
failed();
}
- /*
- * Find the hash using the preprocessed output. Also updates
- * included_files.
- */
- cpp_hash = common_hash;
+ // Find the hash using the preprocessed output. Also updates included_files.
+ struct mdfour cpp_hash = common_hash;
object_hash = calculate_object_hash(preprocessor_args, &cpp_hash, 0);
if (!object_hash) {
fatal("internal error: object hash from cpp returned NULL");
if (object_hash_from_manifest
&& !file_hashes_equal(object_hash_from_manifest, object_hash)) {
- /*
- * The hash from manifest differs from the hash of the
- * preprocessor output. This could be because:
- *
- * - The preprocessor produces different output for the same
- * input (not likely).
- * - There's a bug in ccache (maybe incorrect handling of
- * compiler arguments).
- * - The user has used a different CCACHE_BASEDIR (most
- * likely).
- *
- * The best thing here would probably be to remove the hash
- * entry from the manifest. For now, we use a simpler method:
- * just remove the manifest file.
- */
+ // The hash from manifest differs from the hash of the preprocessor output.
+ // This could be because:
+ //
+ // - The preprocessor produces different output for the same input (not
+ // likely).
+ // - There's a bug in ccache (maybe incorrect handling of compiler
+ // arguments).
+ // - The user has used a different CCACHE_BASEDIR (most likely).
+ //
+ // The best thing here would probably be to remove the hash entry from the
+ // manifest. For now, we use a simpler method: just remove the manifest
+ // file.
cc_log("Hash from manifest doesn't match preprocessor output");
cc_log("Likely reason: different CCACHE_BASEDIRs used");
cc_log("Removing manifest as a safety measure");
put_object_in_manifest = true;
}
- /* if we can return from cache at this point then do */
+ // If we can return from cache at this point then do.
from_cache(FROMCACHE_CPP_MODE, put_object_in_manifest);
if (conf->read_only) {
failed();
}
- add_prefix(compiler_args);
+ add_prefix(compiler_args, conf->prefix_command);
- /* run real compiler, sending output to cache */
+ // Run real compiler, sending output to cache.
to_cache(compiler_args);
x_exit(0);
fprintf(context, "(%s) %s\n", origin, descr);
}
-/* the main program when not doing a compile */
+// The main program when not doing a compile.
static int
ccache_main_options(int argc, char *argv[])
{
- int c;
- char *errmsg;
-
enum longopts {
DUMP_MANIFEST
};
{0, 0, 0, 0}
};
+ int c;
while ((c = getopt_long(argc, argv, "cChF:M:o:psVz", options, NULL)) != -1) {
switch (c) {
case DUMP_MANIFEST:
manifest_dump(optarg, stdout);
break;
- case 'c': /* --cleanup */
+ case 'c': // --cleanup
initialize();
cleanup_all(conf);
printf("Cleaned cache\n");
break;
- case 'C': /* --clear */
+ case 'C': // --clear
initialize();
wipe_all(conf);
printf("Cleared cache\n");
break;
- case 'h': /* --help */
+ case 'h': // --help
fputs(USAGE_TEXT, stdout);
x_exit(0);
- case 'F': /* --max-files */
+ case 'F': // --max-files
{
- unsigned files;
initialize();
- files = atoi(optarg);
+ char *errmsg;
if (conf_set_value_in_file(primary_config_path, "max_files", optarg,
&errmsg)) {
+ unsigned files = atoi(optarg);
if (files == 0) {
printf("Unset cache file limit\n");
} else {
}
break;
- case 'M': /* --max-size */
+ case 'M': // --max-size
{
- uint64_t size;
initialize();
+ uint64_t size;
if (!parse_size_with_suffix(optarg, &size)) {
fatal("invalid size: %s", optarg);
}
+ char *errmsg;
if (conf_set_value_in_file(primary_config_path, "max_size", optarg,
&errmsg)) {
if (size == 0) {
}
break;
- case 'o': /* --set-config */
+ case 'o': // --set-config
{
- char *errmsg, *key, *value, *p;
initialize();
- p = strchr(optarg, '=');
+ char *p = strchr(optarg, '=');
if (!p) {
fatal("missing equal sign in \"%s\"", optarg);
}
- key = x_strndup(optarg, p - optarg);
- value = p + 1;
+ char *key = x_strndup(optarg, p - optarg);
+ char *value = p + 1;
+ char *errmsg;
if (!conf_set_value_in_file(primary_config_path, key, value, &errmsg)) {
fatal("%s", errmsg);
}
}
break;
- case 'p': /* --print-config */
+ case 'p': // --print-config
initialize();
conf_print_items(conf, configuration_printer, stdout);
break;
- case 's': /* --show-stats */
+ case 's': // --show-stats
initialize();
stats_summary(conf);
break;
- case 'V': /* --version */
+ case 'V': // --version
fprintf(stdout, VERSION_TEXT, CCACHE_VERSION);
x_exit(0);
- case 'z': /* --zero-stats */
+ case 'z': // --zero-stats
initialize();
stats_zero();
printf("Statistics cleared\n");
int
ccache_main(int argc, char *argv[])
{
- /* check if we are being invoked as "ccache" */
+ // Check if we are being invoked as "ccache".
char *program_name = basename(argv[0]);
if (same_executable_name(program_name, MYNAME)) {
if (argc < 2) {
fputs(USAGE_TEXT, stderr);
x_exit(1);
}
- /* if the first argument isn't an option, then assume we are
- * being passed a compiler name and options */
+ // If the first argument isn't an option, then assume we are being passed a
+ // compiler name and options.
if (argv[1][0] == '-') {
return ccache_main_options(argc, argv);
}
extern const char CCACHE_VERSION[];
-/* statistics fields in storage order */
+// Statistics fields in storage order.
enum stats {
STATS_NONE = 0,
STATS_STDOUT = 1,
STATS_COMPCHECK = 26,
STATS_CANTUSEPCH = 27,
STATS_PREPROCESSING = 28,
+ STATS_NUMCLEANUPS = 29,
STATS_END
};
#define SLOPPY_FILE_MACRO 4
#define SLOPPY_TIME_MACROS 8
#define SLOPPY_PCH_DEFINES 16
-/*
- * Allow us to match files based on their stats (size, mtime, ctime), without
- * looking at their contents.
- */
+// Allow us to match files based on their stats (size, mtime, ctime), without
+// looking at their contents.
#define SLOPPY_FILE_STAT_MATCHES 32
+// Allow us to not include any system headers in the manifest include files,
+// similar to -MM versus -M for dependencies.
+#define SLOPPY_NO_SYSTEM_HEADERS 64
#define str_eq(s1, s2) (strcmp((s1), (s2)) == 0)
-#define str_startswith(s, p) (strncmp((s), (p), strlen((p))) == 0)
+#define str_startswith(s, prefix) \
+ (strncmp((s), (prefix), strlen((prefix))) == 0)
+#define str_endswith(s, suffix) \
+ (strlen(s) >= strlen(suffix) \
+ && str_eq((s) + strlen(s) - strlen(suffix), (suffix)))
-/* ------------------------------------------------------------------------- */
-/* args.c */
+// Buffer size for I/O operations. Should be a multiple of 4 KiB.
+#define READ_BUFFER_SIZE 65536
+
+// ----------------------------------------------------------------------------
+// args.c
struct args {
char **argv;
char *args_to_string(struct args *args);
bool args_equal(struct args *args1, struct args *args2);
-/* ------------------------------------------------------------------------- */
-/* hash.c */
+// ----------------------------------------------------------------------------
+// hash.c
void hash_start(struct mdfour *md);
void hash_buffer(struct mdfour *md, const void *s, size_t len);
bool hash_fd(struct mdfour *md, int fd);
bool hash_file(struct mdfour *md, const char *fname);
-/* ------------------------------------------------------------------------- */
-/* util.c */
+// ----------------------------------------------------------------------------
+// util.c
void cc_log(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
void cc_bulklog(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
char *get_relative_path(const char *from, const char *to);
bool is_absolute_path(const char *path);
bool is_full_path(const char *path);
+bool is_symlink(const char *path);
void update_mtime(const char *path);
void x_exit(int status) ATTR_NORETURN;
int x_rename(const char *oldpath, const char *newpath);
char *read_text_file(const char *path, size_t size_hint);
char *subst_env_in_string(const char *str, char **errmsg);
-/* ------------------------------------------------------------------------- */
-/* stats.c */
+// ----------------------------------------------------------------------------
+// stats.c
void stats_update(enum stats stat);
void stats_flush(void);
void stats_get_obsolete_limits(const char *dir, unsigned *maxfiles,
uint64_t *maxsize);
void stats_set_sizes(const char *dir, unsigned num_files, uint64_t total_size);
+void stats_add_cleanup(const char *dir, unsigned count);
void stats_read(const char *path, struct counters *counters);
void stats_write(const char *path, struct counters *counters);
-/* ------------------------------------------------------------------------- */
-/* unify.c */
+// ----------------------------------------------------------------------------
+// unify.c
int unify_hash(struct mdfour *hash, const char *fname);
-/* ------------------------------------------------------------------------- */
-/* exitfn.c */
+// ----------------------------------------------------------------------------
+// exitfn.c
void exitfn_init(void);
void exitfn_add_nullary(void (*function)(void));
void exitfn_add(void (*function)(void *), void *context);
void exitfn_call(void);
-/* ------------------------------------------------------------------------- */
-/* cleanup.c */
+// ----------------------------------------------------------------------------
+// cleanup.c
void cleanup_dir(struct conf *conf, const char *dir);
void cleanup_all(struct conf *conf);
void wipe_all(struct conf *conf);
-/* ------------------------------------------------------------------------- */
-/* execute.c */
+// ----------------------------------------------------------------------------
+// execute.c
int execute(char **argv, int fd_out, int fd_err, pid_t *pid);
char *find_executable(const char *name, const char *exclude_name);
void print_command(FILE *fp, char **argv);
-/* ------------------------------------------------------------------------- */
-/* lockfile.c */
+// ----------------------------------------------------------------------------
+// lockfile.c
bool lockfile_acquire(const char *path, unsigned staleness_limit);
void lockfile_release(const char *path);
-/* ------------------------------------------------------------------------- */
-/* ccache.c */
+// ----------------------------------------------------------------------------
+// ccache.c
extern time_t time_of_compilation;
void block_signals(void);
void cc_reset(void);
bool is_precompiled_header(const char *path);
-/* ------------------------------------------------------------------------- */
+// ----------------------------------------------------------------------------
#if HAVE_COMPAR_FN_T
#define COMPAR_FN_T __compar_fn_t
typedef int (*COMPAR_FN_T)(const void *, const void *);
#endif
-/* work with silly DOS binary open */
+// Work with silly DOS binary open.
#ifndef O_BINARY
#define O_BINARY 0
#endif
-/* mkstemp() on some versions of cygwin don't handle binary files, so
- override */
+// mkstemp() on some versions of cygwin don't handle binary files, so override.
#ifdef __CYGWIN__
#undef HAVE_MKSTEMP
#endif
# 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,-1,-1)
-# define execute(a,b,c) win32execute(*(a),a,1,b,c)
+# define execute(a,b,c,d) win32execute(*(a),a,1,b,c)
+# define DIR_DELIM_CH '/'
# define PATH_DELIM ";"
# define F_RDLCK 0
# define F_WRLCK 0
#else
+# define DIR_DELIM_CH '\\'
# define PATH_DELIM ":"
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
-#endif /* ifndef CCACHE_H */
+#endif // ifndef CCACHE_H
-/*
- * Copyright (C) 2002-2006 Andrew Tridgell
- * Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2002-2006 Andrew Tridgell
+// Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
-/*
- * When "max files" or "max cache size" is reached, one of the 16 cache
- * subdirectories is cleaned up. When doing so, files are deleted (in LRU
- * order) until the levels are below LIMIT_MULTIPLE.
- */
-#define LIMIT_MULTIPLE 0.8
-
static struct files {
char *fname;
time_t mtime;
uint64_t size;
} **files;
-static unsigned allocated; /* Size of the files array. */
-static unsigned num_files; /* Number of used entries in the files array. */
+static unsigned allocated; // Size of the files array.
+static unsigned num_files; // Number of used entries in the files array.
static uint64_t cache_size;
static size_t files_in_cache;
static uint64_t cache_size_threshold;
static size_t files_in_cache_threshold;
-/* File comparison function that orders files in mtime order, oldest first. */
+// File comparison function that orders files in mtime order, oldest first.
static int
files_compare(struct files **f1, struct files **f2)
{
return 1;
}
-/* this builds the list of files in the cache */
+// This builds the list of files in the cache.
static void
traverse_fn(const char *fname, struct stat *st)
{
- char *p;
-
if (!S_ISREG(st->st_mode)) {
return;
}
- p = basename(fname);
+ char *p = basename(fname);
if (str_eq(p, "stats")) {
goto out;
}
if (str_startswith(p, ".nfs")) {
- /* Ignore temporary NFS files that may be left for open but deleted
- * files. */
+ // Ignore temporary NFS files that may be left for open but deleted files.
goto out;
}
- if (strstr(p, ".tmp.")) {
- /* delete any tmp files older than 1 hour */
- if (st->st_mtime + 3600 < time(NULL)) {
- x_unlink(fname);
- goto out;
- }
+ // Delete any tmp files older than 1 hour.
+ if (strstr(p, ".tmp.") && st->st_mtime + 3600 < time(NULL)) {
+ x_unlink(fname);
+ goto out;
}
if (strstr(p, "CACHEDIR.TAG")) {
delete_sibling_file(const char *base, const char *extension)
{
struct stat st;
- char *path;
-
- path = format("%s%s", base, extension);
+ char *path = format("%s%s", base, extension);
if (lstat(path, &st) == 0) {
delete_file(path, file_size(&st));
} else if (errno != ENOENT && errno != ESTALE) {
free(path);
}
-/* sort the files we've found and delete the oldest ones until we are
- below the thresholds */
-static void
+// Sort the files we've found and delete the oldest ones until we are below the
+// thresholds.
+static bool
sort_and_clean(void)
{
- unsigned i;
- char *last_base = x_strdup("");
-
if (num_files > 1) {
- /* Sort in ascending mtime order. */
+ // Sort in ascending mtime order.
qsort(files, num_files, sizeof(struct files *), (COMPAR_FN_T)files_compare);
}
- /* delete enough files to bring us below the threshold */
- for (i = 0; i < num_files; i++) {
+ // Delete enough files to bring us below the threshold.
+ char *last_base = x_strdup("");
+ bool cleaned = false;
+ for (unsigned i = 0; i < num_files; i++) {
const char *ext;
if ((cache_size_threshold == 0
|| str_eq(ext, ".stderr")
|| str_eq(ext, "")) {
char *base = remove_extension(files[i]->fname);
- if (!str_eq(base, last_base)) { /* Avoid redundant unlinks. */
- /*
- * Make sure that all sibling files are deleted so that a cached result
- * is removed completely. Note the order of deletions -- the stderr
- * file must be deleted last because if the ccache process gets killed
- * after deleting the .stderr but before deleting the .o, the cached
- * result would be inconsistent.
- */
+ if (!str_eq(base, last_base)) { // Avoid redundant unlinks.
+ // Make sure that all sibling files are deleted so that a cached result
+ // is removed completely. Note the order of deletions -- the stderr
+ // file must be deleted last because if the ccache process gets killed
+ // after deleting the .stderr but before deleting the .o, the cached
+ // result would be inconsistent.
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. */
+ delete_sibling_file(base, ""); // Object file from ccache 2.4.
}
free(last_base);
last_base = base;
} else {
- /* .manifest or unknown file. */
+ // .manifest or unknown file.
delete_file(files[i]->fname, files[i]->size);
}
+ cleaned = true;
}
free(last_base);
+ return cleaned;
}
-/* cleanup in one cache subdir */
+// Clean up one cache subdirectory.
void
cleanup_dir(struct conf *conf, const char *dir)
{
- unsigned i;
-
cc_log("Cleaning up cache directory %s", dir);
- cache_size_threshold = conf->max_size * LIMIT_MULTIPLE / 16;
- files_in_cache_threshold = conf->max_files * LIMIT_MULTIPLE / 16;
+ // When "max files" or "max cache size" is reached, one of the 16 cache
+ // subdirectories is cleaned up. When doing so, files are deleted (in LRU
+ // order) until the levels are below limit_multiple.
+ cache_size_threshold = conf->max_size * conf->limit_multiple / 16;
+ files_in_cache_threshold = conf->max_files * conf->limit_multiple / 16;
num_files = 0;
cache_size = 0;
files_in_cache = 0;
- /* build a list of files */
+ // Build a list of files.
traverse(dir, traverse_fn);
- /* clean the cache */
- sort_and_clean();
+ // Clean the cache.
+ bool cleaned = sort_and_clean();
+ if (cleaned) {
+ cc_log("Cleaned up cache directory %s", dir);
+ stats_add_cleanup(dir, 1);
+ }
stats_set_sizes(dir, files_in_cache, cache_size);
- /* free it up */
- for (i = 0; i < num_files; i++) {
+ // Free it up.
+ for (unsigned i = 0; i < num_files; i++) {
free(files[i]->fname);
free(files[i]);
files[i] = NULL;
files_in_cache = 0;
}
-/* cleanup in all cache subdirs */
+// Clean up all cache subdirectories.
void cleanup_all(struct conf *conf)
{
- int i;
-
- for (i = 0; i <= 0xF; i++) {
+ for (int i = 0; i <= 0xF; i++) {
char *dname = format("%s/%1x", conf->cache_dir, i);
cleanup_dir(conf, dname);
free(dname);
}
}
-/* traverse function for wiping files */
+// Traverse function for wiping files.
static void wipe_fn(const char *fname, struct stat *st)
{
- char *p;
-
if (!S_ISREG(st->st_mode)) {
return;
}
- p = basename(fname);
+ char *p = basename(fname);
if (str_eq(p, "stats")) {
free(p);
return;
}
free(p);
+ files_in_cache++;
+
x_unlink(fname);
}
-/* wipe all cached files in all subdirs */
-void wipe_all(struct conf *conf)
+// Wipe one cache subdirectory.
+void
+wipe_dir(struct conf *conf, const char *dir)
{
- int i;
+ cc_log("Clearing out cache directory %s", dir);
- for (i = 0; i <= 0xF; i++) {
+ files_in_cache_threshold = conf->max_files * conf->limit_multiple / 16;
+ files_in_cache = 0;
+
+ traverse(dir, wipe_fn);
+
+ if (files_in_cache > 0) {
+ cc_log("Cleared out cache directory %s", dir);
+ stats_add_cleanup(dir, 1);
+ }
+
+ files_in_cache = 0;
+}
+
+// Wipe all cached files in all subdirectories.
+void wipe_all(struct conf *conf)
+{
+ for (int i = 0; i <= 0xF; i++) {
char *dname = format("%s/%1x", conf->cache_dir, i);
- traverse(dname, wipe_fn);
+ wipe_dir(conf, dname);
free(dname);
}
- /* and fix the counters */
+ // Fix the counters.
cleanup_all(conf);
}
-/*
- * Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
#include "compopt.h"
{"--save-temps", TOO_HARD},
{"--serialize-diagnostics", TAKES_ARG | TAKES_PATH},
{"-A", TAKES_ARG},
- {"-B", TAKES_ARG | TAKES_CONCAT_ARG},
+ {"-B", TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
{"-D", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG},
{"-E", TOO_HARD},
{"-F", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
{"-MM", TOO_HARD},
{"-MQ", TAKES_ARG},
{"-MT", TAKES_ARG},
+ {"-P", TOO_HARD},
{"-U", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG},
{"-V", TAKES_ARG},
{"-Xassembler", TAKES_ARG},
{"-b", TAKES_ARG},
{"-fmodules", TOO_HARD},
{"-fno-working-directory", AFFECTS_CPP},
- {"-fplugin=libcc1plugin", TOO_HARD}, /* interaction with GDB */
+ {"-fplugin=libcc1plugin", TOO_HARD}, // interaction with GDB
{"-frepo", TOO_HARD},
{"-fstack-usage", TOO_HARD},
{"-fworking-directory", AFFECTS_CPP},
- {"-idirafter", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-idirafter", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
{"-iframework", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
- {"-imacros", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
- {"-imultilib", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
- {"-include", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
- {"-include-pch", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
- {"-install_name", TAKES_ARG}, /* Darwin linker option */
- {"-iprefix", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
- {"-iquote", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
- {"-isysroot", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
- {"-isystem", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
- {"-iwithprefix", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
- {"-iwithprefixbefore", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-imacros", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-imultilib", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-include", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-include-pch", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-install_name", TAKES_ARG}, // Darwin linker option
+ {"-iprefix", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-iquote", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-isysroot", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-isystem", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-iwithprefix", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-iwithprefixbefore",
+ AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
{"-nostdinc", AFFECTS_CPP},
{"-nostdinc++", AFFECTS_CPP},
{"-remap", AFFECTS_CPP},
{"-save-temps", TOO_HARD},
{"-stdlib=", AFFECTS_CPP | TAKES_CONCAT_ARG},
{"-trigraphs", AFFECTS_CPP},
- {"-u", TAKES_ARG},
+ {"-u", TAKES_ARG | TAKES_CONCAT_ARG},
};
sizeof(compopts[0]), compare_prefix_compopts);
}
-/* Runs fn on the first two characters of option. */
+// Runs fn on the first two characters of option.
bool
compopt_short(bool (*fn)(const char *), const char *option)
{
return retval;
}
-/* For test purposes. */
+// For test purposes.
bool
compopt_verify_sortedness(void)
{
- size_t i;
- for (i = 1; i < sizeof(compopts)/sizeof(compopts[0]); i++) {
+ for (size_t i = 1; i < sizeof(compopts)/sizeof(compopts[0]); i++) {
if (strcmp(compopts[i-1].name, compopts[i].name) >= 0) {
fprintf(stderr,
"compopt_verify_sortedness: %s >= %s\n",
return co && (co->type & TAKES_ARG);
}
-/* Determines if the prefix of the option matches any option and affects the
- * preprocessor.
- */
+bool
+compopt_takes_concat_arg(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & TAKES_CONCAT_ARG);
+}
+
+// Determines if the prefix of the option matches any option and affects the
+// preprocessor.
bool
compopt_prefix_affects_cpp(const char *option)
{
- /* prefix options have to take concatentated args */
+ // Prefix options have to take concatentated args.
const struct compopt *co = find_prefix(option);
return co && (co->type & TAKES_CONCAT_ARG) && (co->type & AFFECTS_CPP);
}
bool compopt_too_hard_for_direct_mode(const char *option);
bool compopt_takes_path(const char *option);
bool compopt_takes_arg(const char *option);
+bool compopt_takes_concat_arg(const char *option);
bool compopt_prefix_affects_cpp(const char *option);
-#endif /* CCACHE_COMPOPT_H */
+#endif // CCACHE_COMPOPT_H
-/*
- * Copyright (C) 2011-2014 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2011-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "conf.h"
#include "ccache.h"
}
static bool
+parse_float(const char *str, void *result, char **errmsg)
+{
+ float *value = (float *)result;
+ errno = 0;
+ char *endptr;
+ float x = strtof(str, &endptr);
+ if (errno == 0 && *str != '\0' && *endptr == '\0') {
+ *value = x;
+ return true;
+ } else {
+ *errmsg = format("invalid floating point: \"%s\"", str);
+ return false;
+ }
+}
+
+static bool
parse_size(const char *str, void *result, char **errmsg)
{
uint64_t *value = (uint64_t *)result;
uint64_t size;
- *errmsg = NULL;
if (parse_size_with_suffix(str, &size)) {
*value = size;
return true;
parse_sloppiness(const char *str, void *result, char **errmsg)
{
unsigned *value = (unsigned *)result;
- char *word, *p, *q, *saveptr = NULL;
-
if (!str) {
return *value;
}
- p = x_strdup(str);
- q = p;
+
+ char *p = x_strdup(str);
+ char *q = p;
+ char *word;
+ char *saveptr = NULL;
while ((word = strtok_r(q, ", ", &saveptr))) {
if (str_eq(word, "file_macro")) {
*value |= SLOPPY_FILE_MACRO;
*value |= SLOPPY_INCLUDE_FILE_CTIME;
} else if (str_eq(word, "include_file_mtime")) {
*value |= SLOPPY_INCLUDE_FILE_MTIME;
+ } else if (str_eq(word, "no_system_headers")) {
+ *value |= SLOPPY_NO_SYSTEM_HEADERS;
} else if (str_eq(word, "pch_defines")) {
*value |= SLOPPY_PCH_DEFINES;
} else if (str_eq(word, "time_macros")) {
static bool
parse_string(const char *str, void *result, char **errmsg)
{
- char **value = (char **)result;
(void)errmsg;
+
+ char **value = (char **)result;
free(*value);
*value = x_strdup(str);
return true;
parse_umask(const char *str, void *result, char **errmsg)
{
unsigned *value = (unsigned *)result;
- char *endptr;
if (str_eq(str, "")) {
*value = UINT_MAX;
return true;
}
+
errno = 0;
+ char *endptr;
*value = strtoul(str, &endptr, 8);
if (errno == 0 && *str != '\0' && *endptr == '\0') {
return true;
parse_unsigned(const char *str, void *result, char **errmsg)
{
unsigned *value = (unsigned *)result;
- long x;
- char *endptr;
errno = 0;
- x = strtol(str, &endptr, 10);
+ char *endptr;
+ long x = strtol(str, &endptr, 10);
if (errno == 0 && x >= 0 && *str != '\0' && *endptr == '\0') {
*value = x;
return true;
char **path = (char **)value;
assert(*path);
if (str_eq(*path, "")) {
- /* The empty string means "disable" in this case. */
+ // The empty string means "disable" in this case.
return true;
} else if (is_absolute_path(*path)) {
return true;
char **errmsg, bool from_env_variable, bool negate_boolean,
const char *origin)
{
- const struct conf_item *item;
-
- item = find_conf(key);
+ const struct conf_item *item = find_conf(key);
if (!item) {
*errmsg = format("unknown configuration option \"%s\"", key);
return false;
}
if (from_env_variable && item->parser == parse_bool) {
- /*
- * Special rule for boolean settings from the environment: any value means
- * true.
- */
+ // Special rule for boolean settings from the environment: any value means
+ // true.
bool *value = (bool *)((char *)conf + item->offset);
*value = !negate_boolean;
goto out;
static bool
parse_line(const char *line, char **key, char **value, char **errmsg)
{
- const char *p, *q;
-
#define SKIP_WS(x) while (isspace(*x)) { ++x; }
*key = NULL;
*value = NULL;
- p = line;
+ const char *p = line;
SKIP_WS(p);
if (*p == '\0' || *p == '#') {
return true;
}
- q = p;
+ const char *q = p;
while (isalpha(*q) || *q == '_') {
++q;
}
}
++p;
- /* Skip leading whitespace. */
+ // Skip leading whitespace.
SKIP_WS(p);
q = p;
while (*q) {
++q;
}
- /* Skip trailing whitespace. */
+ // Skip trailing whitespace.
while (isspace(q[-1])) {
--q;
}
#undef SKIP_WS
}
-/* Create a conf struct with default values. */
+// Create a conf struct with default values.
struct conf *
conf_create(void)
{
- size_t i;
struct conf *conf = x_malloc(sizeof(*conf));
conf->base_dir = x_strdup("");
conf->cache_dir = format("%s/.ccache", get_home_directory());
conf->disable = false;
conf->extra_files_to_hash = x_strdup("");
conf->hard_link = false;
- conf->hash_dir = false;
+ conf->hash_dir = true;
+ conf->ignore_headers_in_manifest = x_strdup("");
+ conf->keep_comments_cpp = false;
+ conf->limit_multiple = 0.8f;
conf->log_file = x_strdup("");
conf->max_files = 0;
conf->max_size = (uint64_t)5 * 1000 * 1000 * 1000;
conf->path = x_strdup("");
conf->prefix_command = x_strdup("");
+ conf->prefix_command_cpp = x_strdup("");
conf->read_only = false;
conf->read_only_direct = false;
conf->recache = false;
- conf->run_second_cpp = false;
+ conf->run_second_cpp = true;
conf->sloppiness = 0;
conf->stats = true;
conf->temporary_dir = x_strdup("");
- conf->umask = UINT_MAX; /* default: don't set umask */
+ conf->umask = UINT_MAX; // Default: don't set umask.
conf->unify = false;
conf->item_origins = x_malloc(CONFITEMS_TOTAL_KEYWORDS * sizeof(char *));
- for (i = 0; i < CONFITEMS_TOTAL_KEYWORDS; ++i) {
+ for (size_t i = 0; i < CONFITEMS_TOTAL_KEYWORDS; ++i) {
conf->item_origins[i] = "default";
}
return conf;
free(conf->compiler_check);
free(conf->cpp_extension);
free(conf->extra_files_to_hash);
+ free(conf->ignore_headers_in_manifest);
free(conf->log_file);
free(conf->path);
free(conf->prefix_command);
+ free(conf->prefix_command_cpp);
free(conf->temporary_dir);
free(conf->item_origins);
free(conf);
}
-/* Note: The path pointer is stored in conf, so path must outlive conf. */
+// Note: The path pointer is stored in conf, so path must outlive conf.
bool
conf_read(struct conf *conf, const char *path, char **errmsg)
{
- FILE *f;
- char buf[10000];
- bool result = true;
- unsigned line_number;
-
assert(errmsg);
*errmsg = NULL;
- f = fopen(path, "r");
+ FILE *f = fopen(path, "r");
if (!f) {
*errmsg = format("%s: %s", path, strerror(errno));
return false;
}
- line_number = 0;
+ unsigned line_number = 0;
+ bool result = true;
+ char buf[10000];
while (fgets(buf, sizeof(buf), f)) {
- char *errmsg2, *key, *value;
- bool ok;
++line_number;
- ok = parse_line(buf, &key, &value, &errmsg2);
- if (ok && key) { /* key == NULL if comment or blank line */
+
+ char *key;
+ char *value;
+ char *errmsg2;
+ bool ok = parse_line(buf, &key, &value, &errmsg2);
+ if (ok && key) { // key == NULL if comment or blank line.
ok = handle_conf_setting(conf, key, value, &errmsg2, false, false, path);
}
free(key);
bool
conf_update_from_environment(struct conf *conf, char **errmsg)
{
- char **p;
- char *q;
- char *key;
- char *errmsg2;
- const struct env_to_conf_item *env_to_conf_item;
- bool negate;
- size_t key_start;
-
- for (p = environ; *p; ++p) {
+ for (char **p = environ; *p; ++p) {
if (!str_startswith(*p, "CCACHE_")) {
continue;
}
- q = strchr(*p, '=');
+ char *q = strchr(*p, '=');
if (!q) {
continue;
}
+ bool negate;
+ size_t key_start;
if (str_startswith(*p + 7, "NO")) {
negate = true;
key_start = 9;
negate = false;
key_start = 7;
}
- key = x_strndup(*p + key_start, q - *p - key_start);
+ char *key = x_strndup(*p + key_start, q - *p - key_start);
- ++q; /* Now points to the value. */
+ ++q; // Now points to the value.
- env_to_conf_item = find_env_to_conf(key);
+ const struct env_to_conf_item *env_to_conf_item = find_env_to_conf(key);
if (!env_to_conf_item) {
free(key);
continue;
}
+ char *errmsg2;
if (!handle_conf_setting(
conf, env_to_conf_item->conf_name, q, &errmsg2, true, negate,
"environment")) {
conf_set_value_in_file(const char *path, const char *key, const char *value,
char **errmsg)
{
- FILE *infile, *outfile;
- char *outpath;
- char buf[10000];
- bool found;
- const struct conf_item *item;
-
- item = find_conf(key);
+ const struct conf_item *item = find_conf(key);
if (!item) {
*errmsg = format("unknown configuration option \"%s\"", key);
return false;
}
- infile = fopen(path, "r");
+ FILE *infile = fopen(path, "r");
if (!infile) {
*errmsg = format("%s: %s", path, strerror(errno));
return false;
}
- outpath = format("%s.tmp", path);
- outfile = create_tmp_file(&outpath, "w");
+ char *outpath = format("%s.tmp", path);
+ FILE *outfile = create_tmp_file(&outpath, "w");
if (!outfile) {
*errmsg = format("%s: %s", outpath, strerror(errno));
free(outpath);
return false;
}
- found = false;
+ bool found = false;
+ char buf[10000];
while (fgets(buf, sizeof(buf), infile)) {
- char *errmsg2, *key2, *value2;
- bool ok;
- ok = parse_line(buf, &key2, &value2, &errmsg2);
+ char *key2;
+ char *value2;
+ char *errmsg2;
+ bool ok = parse_line(buf, &key2, &value2, &errmsg2);
if (ok && key2 && str_eq(key2, key)) {
found = true;
fprintf(outfile, "%s = %s\n", key, value);
void *context)
{
char *s = x_strdup("");
- char *s2;
reformat(&s, "base_dir = %s", conf->base_dir);
printer(s, conf->item_origins[find_conf("base_dir")->number], context);
reformat(&s, "hash_dir = %s", bool_to_string(conf->hash_dir));
printer(s, conf->item_origins[find_conf("hash_dir")->number], context);
+ reformat(&s, "ignore_headers_in_manifest = %s",
+ conf->ignore_headers_in_manifest);
+ printer(s,
+ conf->item_origins[find_conf("ignore_headers_in_manifest")->number],
+ context);
+
+ reformat(&s, "keep_comments_cpp = %s",
+ bool_to_string(conf->keep_comments_cpp));
+ printer(s, conf->item_origins[find_conf(
+ "keep_comments_cpp")->number], context);
+
+ reformat(&s, "limit_multiple = %.1f", (double)conf->limit_multiple);
+ printer(s, conf->item_origins[find_conf("limit_multiple")->number], context);
+
reformat(&s, "log_file = %s", conf->log_file);
printer(s, conf->item_origins[find_conf("log_file")->number], context);
reformat(&s, "max_files = %u", conf->max_files);
printer(s, conf->item_origins[find_conf("max_files")->number], context);
- s2 = format_parsable_size_with_suffix(conf->max_size);
+ char *s2 = format_parsable_size_with_suffix(conf->max_size);
reformat(&s, "max_size = %s", s2);
printer(s, conf->item_origins[find_conf("max_size")->number], context);
free(s2);
reformat(&s, "prefix_command = %s", conf->prefix_command);
printer(s, conf->item_origins[find_conf("prefix_command")->number], context);
+ reformat(&s, "prefix_command_cpp = %s", conf->prefix_command_cpp);
+ printer(s, conf->item_origins[find_conf(
+ "prefix_command_cpp")->number], context);
+
reformat(&s, "read_only = %s", bool_to_string(conf->read_only));
printer(s, conf->item_origins[find_conf("read_only")->number], context);
if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) {
reformat(&s, "%sfile_stat_matches, ", s);
}
+ if (conf->sloppiness & SLOPPY_NO_SYSTEM_HEADERS) {
+ reformat(&s, "%sno_system_headers, ", s);
+ }
if (conf->sloppiness) {
- /* Strip last ", ". */
+ // Strip last ", ".
s[strlen(s) - 2] = '\0';
}
printer(s, conf->item_origins[find_conf("sloppiness")->number], context);
char *extra_files_to_hash;
bool hard_link;
bool hash_dir;
+ char *ignore_headers_in_manifest;
+ bool keep_comments_cpp;
+ float limit_multiple;
char *log_file;
unsigned max_files;
uint64_t max_size;
char *path;
char *prefix_command;
+ char *prefix_command_cpp;
bool read_only;
bool read_only_direct;
bool recache;
/* Define to 1 if your compiler supports extern inline */
#undef HAVE_EXTERN_INLINE
+/* Define to 1 if you have the `GetFinalPathNameByHandleW' function. */
+#undef HAVE_GETFINALPATHNAMEBYHANDLEW
+
/* Define to 1 if you have the `gethostname' function. */
#undef HAVE_GETHOSTNAME
/* Define to 1 if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H
-/* Define to 1 if stdbool.h conforms to C99. */
-#undef HAVE_STDBOOL_H
-
/* Define to 1 if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H
/* Define to 1 if you have a C99 compliant `vsnprintf' function. */
#undef HAVE_VSNPRINTF
-/* Define to 1 if the system has the type `_Bool'. */
-#undef HAVE__BOOL
-
/* Define to 1 if you have the `__va_copy' function or macro. */
#undef HAVE___VA_COPY
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if ${ac_cv_prog_cc_c99+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+#define debug(...) fprintf (stderr, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ your preprocessor is broken;
+#endif
+#if BIG_OK
+#else
+ your preprocessor is broken;
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict (ccp restrict text)
+{
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+ continue;
+ return 0;
+}
+
+// Check varargs and va_copy.
+static void
+test_varargs (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
+
+ const char *str;
+ int number;
+ float fnumber;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case 's': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case 'd': // int
+ number = va_arg (args_copy, int);
+ break;
+ case 'f': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
+}
+
+int
+main ()
+{
+
+ // Check bool.
+ _Bool success = false;
+
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
+
+ // Check varargs.
+ test_varargs ("s, d' f .", "string", 65, 34.234);
+ test_varargs_macros ();
+
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
+
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
+
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[ni.number - 1] = 543;
+
+ // work around unused variable warnings
+ return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
+ || dynamic_array[ni.number - 1] != 543);
+
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c99" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c99"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c99" != xno; then :
+
+fi
+
+
+if test "$ac_cv_prog_cc_c99" = no; then
+ as_fn_error $? "cannot find a C99-compatible compiler" "$LINENO" 5
+fi
+
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5
+$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
+if ${ac_cv_header_sys_wait_h+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+int
+main ()
+{
+ int s;
+ wait (&s);
+ s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_sys_wait_h=yes
+else
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5
+$as_echo "$ac_cv_header_sys_wait_h" >&6; }
+if test $ac_cv_header_sys_wait_h = yes; then
+
+$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
+
+fi
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
done
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5
-$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; }
-if ${ac_cv_header_stdbool_h+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
- #include <stdbool.h>
- #ifndef bool
- "error: bool is not defined"
- #endif
- #ifndef false
- "error: false is not defined"
- #endif
- #if false
- "error: false is not 0"
- #endif
- #ifndef true
- "error: true is not defined"
- #endif
- #if true != 1
- "error: true is not 1"
- #endif
- #ifndef __bool_true_false_are_defined
- "error: __bool_true_false_are_defined is not defined"
- #endif
-
- struct s { _Bool s: 1; _Bool t; } s;
-
- char a[true == 1 ? 1 : -1];
- char b[false == 0 ? 1 : -1];
- char c[__bool_true_false_are_defined == 1 ? 1 : -1];
- char d[(bool) 0.5 == true ? 1 : -1];
- /* See body of main program for 'e'. */
- char f[(_Bool) 0.0 == false ? 1 : -1];
- char g[true];
- char h[sizeof (_Bool)];
- char i[sizeof s.t];
- enum { j = false, k = true, l = false * true, m = true * 256 };
- /* The following fails for
- HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */
- _Bool n[m];
- char o[sizeof n == m * sizeof n[0] ? 1 : -1];
- char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1];
- /* Catch a bug in an HP-UX C compiler. See
- http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html
- http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html
- */
- _Bool q = true;
- _Bool *pq = &q;
-
-int
-main ()
-{
-
- bool e = &s;
- *pq |= q;
- *pq |= ! q;
- /* Refer to every declared value, to avoid compiler optimizations. */
- return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l
- + !m + !n + !o + !p + !q + !pq);
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_header_stdbool_h=yes
-else
- ac_cv_header_stdbool_h=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5
-$as_echo "$ac_cv_header_stdbool_h" >&6; }
- ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default"
-if test "x$ac_cv_type__Bool" = xyes; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE__BOOL 1
-_ACEOF
-
-
-fi
-
-
-if test $ac_cv_header_stdbool_h = yes; then
-
-$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h
-
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5
-$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
-if ${ac_cv_header_sys_wait_h+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
-#include <sys/wait.h>
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
-#endif
-#ifndef WIFEXITED
-# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
-#endif
-
-int
-main ()
-{
- int s;
- wait (&s);
- s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_header_sys_wait_h=yes
-else
- ac_cv_header_sys_wait_h=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5
-$as_echo "$ac_cv_header_sys_wait_h" >&6; }
-if test $ac_cv_header_sys_wait_h = yes; then
-
-$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
-
-fi
-
-
ac_fn_c_check_type "$LINENO" "long long" "ac_cv_type_long_long" "$ac_includes_default"
if test "x$ac_cv_type_long_long" = xyes; then :
if test x${windows_os} = xyes; then
LIBS="$LIBS -lws2_32"
+ for ac_func in GetFinalPathNameByHandleW
+do :
+ ac_fn_c_check_func "$LINENO" "GetFinalPathNameByHandleW" "ac_cv_func_GetFinalPathNameByHandleW"
+if test "x$ac_cv_func_GetFinalPathNameByHandleW" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETFINALPATHNAMEBYHANDLEW 1
+_ACEOF
+
+else
+ LIBS="$LIBS -lpsapi"
+fi
+done
+
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
AC_SUBST(test_suites)
dnl Checks for programs.
-AC_PROG_CC
+AC_PROG_CC_C99
+if test "$ac_cv_prog_cc_c99" = no; then
+ AC_MSG_ERROR(cannot find a C99-compatible compiler)
+fi
+
AC_PROG_CPP
AC_PROG_INSTALL
AC_PROG_RANLIB
AC_HEADER_DIRENT
AC_HEADER_TIME
-AC_HEADER_STDBOOL
AC_HEADER_SYS_WAIT
AC_CHECK_TYPES(long long)
dnl Linking on Windows needs ws2_32
if test x${windows_os} = xyes; then
LIBS="$LIBS -lws2_32"
+ AC_CHECK_FUNCS(GetFinalPathNameByHandleW,[],[LIBS="$LIBS -lpsapi"])
fi
AC_C_BIGENDIAN
extra_files_to_hash, 10, ITEM(extra_files_to_hash, env_string)
hard_link, 11, ITEM(hard_link, bool)
hash_dir, 12, ITEM(hash_dir, bool)
-log_file, 13, ITEM(log_file, env_string)
-max_files, 14, ITEM(max_files, unsigned)
-max_size, 15, ITEM(max_size, size)
-path, 16, ITEM(path, env_string)
-prefix_command, 17, ITEM(prefix_command, env_string)
-read_only, 18, ITEM(read_only, bool)
-read_only_direct, 19, ITEM(read_only_direct, bool)
-recache, 20, ITEM(recache, bool)
-run_second_cpp, 21, ITEM(run_second_cpp, bool)
-sloppiness, 22, ITEM(sloppiness, sloppiness)
-stats, 23, ITEM(stats, bool)
-temporary_dir, 24, ITEM(temporary_dir, env_string)
-umask, 25, ITEM(umask, umask)
-unify, 26, ITEM(unify, bool)
+ignore_headers_in_manifest, 13, ITEM(ignore_headers_in_manifest, env_string)
+keep_comments_cpp, 14, ITEM(keep_comments_cpp, bool)
+limit_multiple, 15, ITEM(limit_multiple, float)
+log_file, 16, ITEM(log_file, env_string)
+max_files, 17, ITEM(max_files, unsigned)
+max_size, 18, ITEM(max_size, size)
+path, 19, ITEM(path, env_string)
+prefix_command, 20, ITEM(prefix_command, env_string)
+prefix_command_cpp, 21, ITEM(prefix_command_cpp, env_string)
+read_only, 22, ITEM(read_only, bool)
+read_only_direct, 23, ITEM(read_only_direct, bool)
+recache, 24, ITEM(recache, bool)
+run_second_cpp, 25, ITEM(run_second_cpp, bool)
+sloppiness, 26, ITEM(sloppiness, sloppiness)
+stats, 27, ITEM(stats, bool)
+temporary_dir, 28, ITEM(temporary_dir, env_string)
+umask, 29, ITEM(umask, umask)
+unify, 30, ITEM(unify, bool)
#line 8 "confitems.gperf"
struct conf_item;
-/* maximum key range = 45, duplicates = 0 */
+/* maximum key range = 46, duplicates = 0 */
#ifdef __GNUC__
__inline
50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50, 50, 50, 50, 20, 5, 0,
- 10, 0, 50, 50, 15, 5, 50, 50, 20, 10,
- 0, 0, 10, 50, 0, 0, 0, 5, 50, 50,
- 30, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 0, 13, 0,
+ 5, 10, 50, 0, 30, 20, 50, 0, 10, 20,
+ 5, 0, 0, 50, 5, 0, 10, 15, 50, 50,
+ 20, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
{
enum
{
- TOTAL_KEYWORDS = 27,
+ TOTAL_KEYWORDS = 31,
MIN_WORD_LENGTH = 4,
- MAX_WORD_LENGTH = 19,
- MIN_HASH_VALUE = 5,
+ MAX_WORD_LENGTH = 26,
+ MIN_HASH_VALUE = 4,
MAX_HASH_VALUE = 49
};
{
{"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
{"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
+#line 29 "confitems.gperf"
+ {"path", 19, ITEM(path, env_string)},
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
{"",0,NULL,0,NULL},
-#line 33 "confitems.gperf"
- {"stats", 23, ITEM(stats, bool)},
- {"",0,NULL,0,NULL},
-#line 30 "confitems.gperf"
- {"recache", 20, ITEM(recache, bool)},
#line 13 "confitems.gperf"
{"compiler", 3, ITEM(compiler, string)},
-#line 28 "confitems.gperf"
- {"read_only", 18, ITEM(read_only, bool)},
-#line 36 "confitems.gperf"
- {"unify", 26, ITEM(unify, bool)},
+#line 11 "confitems.gperf"
+ {"cache_dir", 1, ITEM(cache_dir, env_string)},
+ {"",0,NULL,0,NULL},
#line 15 "confitems.gperf"
{"compression", 5, ITEM(compression, bool)},
{"",0,NULL,0,NULL},
-#line 34 "confitems.gperf"
- {"temporary_dir", 24, ITEM(temporary_dir, env_string)},
+#line 17 "confitems.gperf"
+ {"cpp_extension", 7, ITEM(cpp_extension, string)},
#line 14 "confitems.gperf"
{"compiler_check", 4, ITEM(compiler_check, string)},
- {"",0,NULL,0,NULL},
-#line 29 "confitems.gperf"
- {"read_only_direct", 19, ITEM(read_only_direct, bool)},
+#line 37 "confitems.gperf"
+ {"stats", 27, ITEM(stats, bool)},
+#line 12 "confitems.gperf"
+ {"cache_dir_levels", 2, ITEM_V(cache_dir_levels, unsigned, dir_levels)},
#line 16 "confitems.gperf"
{"compression_level", 6, ITEM(compression_level, unsigned)},
- {"",0,NULL,0,NULL},
+#line 26 "confitems.gperf"
+ {"log_file", 16, ITEM(log_file, env_string)},
+#line 30 "confitems.gperf"
+ {"prefix_command", 20, ITEM(prefix_command, env_string)},
+#line 36 "confitems.gperf"
+ {"sloppiness", 26, ITEM(sloppiness, sloppiness)},
+#line 10 "confitems.gperf"
+ {"base_dir", 0, ITEM_V(base_dir, env_string, absolute_path)},
+#line 34 "confitems.gperf"
+ {"recache", 24, ITEM(recache, bool)},
#line 31 "confitems.gperf"
- {"run_second_cpp", 21, ITEM(run_second_cpp, bool)},
-#line 35 "confitems.gperf"
- {"umask", 25, ITEM(umask, umask)},
+ {"prefix_command_cpp", 21, ITEM(prefix_command_cpp, env_string)},
+#line 32 "confitems.gperf"
+ {"read_only", 22, ITEM(read_only, bool)},
+#line 40 "confitems.gperf"
+ {"unify", 30, ITEM(unify, bool)},
{"",0,NULL,0,NULL},
+#line 24 "confitems.gperf"
+ {"keep_comments_cpp", 14, ITEM(keep_comments_cpp, bool)},
+#line 28 "confitems.gperf"
+ {"max_size", 18, ITEM(max_size, size)},
+#line 27 "confitems.gperf"
+ {"max_files", 17, ITEM(max_files, unsigned)},
+ {"",0,NULL,0,NULL},
+#line 33 "confitems.gperf"
+ {"read_only_direct", 23, ITEM(read_only_direct, bool)},
#line 19 "confitems.gperf"
{"disable", 9, ITEM(disable, bool)},
-#line 17 "confitems.gperf"
- {"cpp_extension", 7, ITEM(cpp_extension, string)},
-#line 27 "confitems.gperf"
- {"prefix_command", 17, ITEM(prefix_command, env_string)},
+#line 38 "confitems.gperf"
+ {"temporary_dir", 28, ITEM(temporary_dir, env_string)},
+#line 35 "confitems.gperf"
+ {"run_second_cpp", 25, ITEM(run_second_cpp, bool)},
{"",0,NULL,0,NULL},
#line 18 "confitems.gperf"
{"direct_mode", 8, ITEM(direct_mode, bool)},
{"",0,NULL,0,NULL},
-#line 23 "confitems.gperf"
- {"log_file", 13, ITEM(log_file, env_string)},
-#line 11 "confitems.gperf"
- {"cache_dir", 1, ITEM(cache_dir, env_string)},
-#line 32 "confitems.gperf"
- {"sloppiness", 22, ITEM(sloppiness, sloppiness)},
- {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
-#line 10 "confitems.gperf"
- {"base_dir", 0, ITEM_V(base_dir, env_string, absolute_path)},
-#line 26 "confitems.gperf"
- {"path", 16, ITEM(path, env_string)},
- {"",0,NULL,0,NULL},
-#line 12 "confitems.gperf"
- {"cache_dir_levels", 2, ITEM_V(cache_dir_levels, unsigned, dir_levels)},
- {"",0,NULL,0,NULL},
-#line 25 "confitems.gperf"
- {"max_size", 15, ITEM(max_size, size)},
-#line 24 "confitems.gperf"
- {"max_files", 14, ITEM(max_files, unsigned)},
- {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
- {"",0,NULL,0,NULL},
#line 22 "confitems.gperf"
{"hash_dir", 12, ITEM(hash_dir, bool)},
#line 21 "confitems.gperf"
{"hard_link", 11, ITEM(hard_link, bool)},
+#line 39 "confitems.gperf"
+ {"umask", 29, ITEM(umask, umask)},
{"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
+ {"",0,NULL,0,NULL},
+#line 25 "confitems.gperf"
+ {"limit_multiple", 15, ITEM(limit_multiple, float)},
+ {"",0,NULL,0,NULL},
+#line 23 "confitems.gperf"
+ {"ignore_headers_in_manifest", 13, ITEM(ignore_headers_in_manifest, env_string)},
{"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
#line 20 "confitems.gperf"
{"extra_files_to_hash", 10, ITEM(extra_files_to_hash, env_string)}
}
return 0;
}
-static const size_t CONFITEMS_TOTAL_KEYWORDS = 27;
+static const size_t CONFITEMS_TOTAL_KEYWORDS = 31;
-/*
- * Copyright (C) 2010 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-/* A simple array of unsigned integers used for the statistics counters. */
+// A simple array of unsigned integers used for the statistics counters.
#include "ccache.h"
-/*
- * Allocate and initialize a struct counters. Data entries up to the size are
- * set to 0.
- */
+// Allocate and initialize a struct counters. Data entries up to the size are
+// set to 0.
struct counters *
counters_init(size_t initial_size)
{
return c;
}
-/*
- * Free a struct counters.
- */
+// Free a counters struct.
void
counters_free(struct counters *c)
{
free(c);
}
-/*
- * Set a new size. New data entries are set to 0.
- */
+// Set a new size. New data entries are set to 0.
void
counters_resize(struct counters *c, size_t new_size)
{
if (new_size > c->size) {
- size_t i;
bool realloc = false;
-
while (c->allocated < new_size) {
c->allocated += 32 + c->allocated;
realloc = true;
if (realloc) {
c->data = x_realloc(c->data, c->allocated * sizeof(c->data[0]));
}
- for (i = c->size; i < new_size; i++) {
+ for (size_t i = c->size; i < new_size; i++) {
c->data[i] = 0;
}
}
-/*
- * Copyright (C) 2010 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef COUNTERS_H
#define COUNTERS_H
+#include <stddef.h>
+
struct counters {
- unsigned *data; /* counter value */
- size_t size; /* logical array size */
- size_t allocated; /* allocated size */
+ unsigned *data; // counter value
+ size_t size; // logical array size
+ size_t allocated; // allocated size
};
struct counters *counters_init(size_t initial_size);
dist_archives += ccache-$(version).tar.xz
endif
-generated_docs = \
- ccache.1 AUTHORS.html INSTALL.html LICENSE.html MANUAL.html NEWS.html \
- README.html
+generated_docs = ccache.1 AUTHORS.html LICENSE.html MANUAL.html NEWS.html
built_dist_files = $(generated_docs)
headers = \
test/suites.h \
test/util.h
-files_to_clean += *.tar.bz2 *.tar.gz *.tar.xz *.xml .deps/*
+files_to_clean += *.tar.bz2 *.tar.gz *.tar.xz *.xml .deps/* perfdir.*
files_to_distclean += $(built_dist_files) version.c test/suites.h
files_to_distclean += .deps version.c dev.mk
AUTHORS.txt \
GPL-3.0.txt \
HACKING.txt \
- INSTALL.txt \
LICENSE.txt \
MANUAL.txt \
Makefile.in \
NEWS.txt \
- README.txt \
+ README.md \
autogen.sh \
config.guess \
config.h.in \
mkdir $$dir && \
(cd $(srcdir) && \
rsync -r --relative $(source_dist_files) $$dir) && \
+ cp $(srcdir)/INSTALL-from-release-archive.md $$dir/INSTALL.md && \
cp $(built_dist_files) $$dir && \
echo "Remove this file to enable developer mode." >$$dir/dev_mode_disabled && \
(cd $$tmpdir && \
COMPRESS, "compression"
COMPRESSLEVEL, "compression_level"
CPP2, "run_second_cpp"
+COMMENTS, "keep_comments_cpp"
DIR, "cache_dir"
DIRECT, "direct_mode"
DISABLE, "disable"
EXTRAFILES, "extra_files_to_hash"
HARDLINK, "hard_link"
HASHDIR, "hash_dir"
+IGNOREHEADERS, "ignore_headers_in_manifest"
+LIMIT_MULTIPLE, "limit_multiple"
LOGFILE, "log_file"
MAXFILES, "max_files"
MAXSIZE, "max_size"
NLEVELS, "cache_dir_levels"
PATH, "path"
PREFIX, "prefix_command"
+PREFIX_CPP, "prefix_command_cpp"
READONLY, "read_only"
READONLY_DIRECT, "read_only_direct"
RECACHE, "recache"
#line 9 "envtoconfitems.gperf"
struct env_to_conf_item;
-/* maximum key range = 41, duplicates = 0 */
+/* maximum key range = 42, duplicates = 0 */
#ifdef __GNUC__
__inline
{
static const unsigned char asso_values[] =
{
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 20, 0, 0, 10,
- 20, 43, 15, 43, 10, 43, 5, 10, 15, 0,
- 5, 10, 5, 0, 0, 0, 43, 43, 43, 43,
- 10, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 20, 0, 0, 10,
+ 0, 44, 5, 15, 0, 44, 10, 25, 9, 0,
+ 5, 10, 5, 15, 10, 5, 44, 44, 44, 44,
+ 0, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44
};
register int hval = len;
{
enum
{
- TOTAL_KEYWORDS = 27,
+ TOTAL_KEYWORDS = 31,
MIN_WORD_LENGTH = 2,
MAX_WORD_LENGTH = 15,
MIN_HASH_VALUE = 2,
- MAX_HASH_VALUE = 42
+ MAX_HASH_VALUE = 43
};
static const struct env_to_conf_item wordlist[] =
{"",""}, {"",""},
#line 12 "envtoconfitems.gperf"
{"CC", "compiler"},
-#line 17 "envtoconfitems.gperf"
+#line 18 "envtoconfitems.gperf"
{"DIR", "cache_dir"},
#line 16 "envtoconfitems.gperf"
{"CPP2", "run_second_cpp"},
-#line 34 "envtoconfitems.gperf"
- {"STATS", "stats"},
-#line 18 "envtoconfitems.gperf"
- {"DIRECT", "direct_mode"},
+ {"",""},
#line 19 "envtoconfitems.gperf"
+ {"DIRECT", "direct_mode"},
+#line 20 "envtoconfitems.gperf"
{"DISABLE", "disable"},
-#line 14 "envtoconfitems.gperf"
- {"COMPRESS", "compression"},
-#line 28 "envtoconfitems.gperf"
+#line 17 "envtoconfitems.gperf"
+ {"COMMENTS", "keep_comments_cpp"},
+#line 31 "envtoconfitems.gperf"
{"PATH", "path"},
-#line 36 "envtoconfitems.gperf"
- {"UMASK", "umask"},
- {"",""},
+#line 41 "envtoconfitems.gperf"
+ {"UNIFY", "unify"},
#line 32 "envtoconfitems.gperf"
+ {"PREFIX", "prefix_command"},
+#line 36 "envtoconfitems.gperf"
{"RECACHE", "recache"},
-#line 15 "envtoconfitems.gperf"
- {"COMPRESSLEVEL", "compression_level"},
- {"",""},
-#line 37 "envtoconfitems.gperf"
- {"UNIFY", "unify"},
+#line 13 "envtoconfitems.gperf"
+ {"COMPILERCHECK", "compiler_check"},
{"",""},
-#line 35 "envtoconfitems.gperf"
- {"TEMPDIR", "temporary_dir"},
+#line 33 "envtoconfitems.gperf"
+ {"PREFIX_CPP", "prefix_command_cpp"},
#line 30 "envtoconfitems.gperf"
+ {"NLEVELS", "cache_dir_levels"},
+#line 27 "envtoconfitems.gperf"
+ {"LOGFILE", "log_file"},
+#line 34 "envtoconfitems.gperf"
{"READONLY", "read_only"},
-#line 20 "envtoconfitems.gperf"
+#line 21 "envtoconfitems.gperf"
{"EXTENSION", "cpp_extension"},
-#line 33 "envtoconfitems.gperf"
- {"SLOPPINESS", "sloppiness"},
-#line 29 "envtoconfitems.gperf"
- {"PREFIX", "prefix_command"},
+#line 40 "envtoconfitems.gperf"
+ {"UMASK", "umask"},
+ {"",""},
#line 24 "envtoconfitems.gperf"
- {"LOGFILE", "log_file"},
-#line 13 "envtoconfitems.gperf"
- {"COMPILERCHECK", "compiler_check"},
+ {"HASHDIR", "hash_dir"},
+#line 14 "envtoconfitems.gperf"
+ {"COMPRESS", "compression"},
{"",""},
-#line 31 "envtoconfitems.gperf"
+#line 35 "envtoconfitems.gperf"
{"READONLY_DIRECT", "read_only_direct"},
{"",""},
+#line 39 "envtoconfitems.gperf"
+ {"TEMPDIR", "temporary_dir"},
+#line 15 "envtoconfitems.gperf"
+ {"COMPRESSLEVEL", "compression_level"},
#line 26 "envtoconfitems.gperf"
+ {"LIMIT_MULTIPLE", "limit_multiple"},
+#line 38 "envtoconfitems.gperf"
+ {"STATS", "stats"},
+ {"",""},
+#line 29 "envtoconfitems.gperf"
{"MAXSIZE", "max_size"},
-#line 25 "envtoconfitems.gperf"
+#line 28 "envtoconfitems.gperf"
{"MAXFILES", "max_files"},
- {"",""}, {"",""}, {"",""},
-#line 23 "envtoconfitems.gperf"
- {"HASHDIR", "hash_dir"},
-#line 22 "envtoconfitems.gperf"
- {"HARDLINK", "hard_link"},
- {"",""}, {"",""}, {"",""},
+ {"",""},
+#line 37 "envtoconfitems.gperf"
+ {"SLOPPINESS", "sloppiness"},
+ {"",""},
#line 11 "envtoconfitems.gperf"
{"BASEDIR", "base_dir"},
- {"",""}, {"",""},
-#line 21 "envtoconfitems.gperf"
- {"EXTRAFILES", "extra_files_to_hash"},
+#line 23 "envtoconfitems.gperf"
+ {"HARDLINK", "hard_link"},
{"",""},
-#line 27 "envtoconfitems.gperf"
- {"NLEVELS", "cache_dir_levels"}
+#line 22 "envtoconfitems.gperf"
+ {"EXTRAFILES", "extra_files_to_hash"},
+ {"",""}, {"",""},
+#line 25 "envtoconfitems.gperf"
+ {"IGNOREHEADERS", "ignore_headers_in_manifest"}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
}
return 0;
}
-static const size_t ENVTOCONFITEMS_TOTAL_KEYWORDS = 27;
+static const size_t ENVTOCONFITEMS_TOTAL_KEYWORDS = 31;
-/*
- * Copyright (C) Andrew Tridgell 2002
- * Copyright (C) Joel Rosdahl 2011
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2002 Andrew Tridgell
+// Copyright (C) 2011-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
find_executable_in_path(const char *name, const char *exclude_name, char *path);
#ifdef _WIN32
-/*
- * Re-create a win32 command line string based on **argv.
- * http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
- */
+// Re-create a win32 command line string based on **argv.
+// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
char *
win32argvtos(char *prefix, char **argv)
{
- char *arg;
- char *ptr;
- char *str;
- int l = 0;
- int i, j;
-
- i = 0;
- arg = prefix ? prefix : argv[i++];
+ int i = 0;
+ int k = 0;
+ char *arg = prefix ? prefix : argv[i++];
do {
int bs = 0;
- for (j = 0; arg[j]; j++) {
+ for (int j = 0; arg[j]; j++) {
switch (arg[j]) {
case '\\':
bs++;
case '"':
bs = (bs << 1) + 1;
default:
- l += bs + 1;
+ k += bs + 1;
bs = 0;
}
}
- l += (bs << 1) + 3;
+ k += (bs << 1) + 3;
} while ((arg = argv[i++]));
- str = ptr = malloc(l + 1);
- if (!str)
+ char *ptr = malloc(k + 1);
+ char *str = ptr;
+ if (!str) {
return NULL;
+ }
i = 0;
arg = prefix ? prefix : argv[i++];
do {
int bs = 0;
*ptr++ = '"';
- for (j = 0; arg[j]; j++) {
+ for (int j = 0; arg[j]; j++) {
switch (arg[j]) {
case '\\':
bs++;
case '"':
bs = (bs << 1) + 1;
default:
- while (bs && bs--)
+ while (bs && bs--) {
*ptr++ = '\\';
+ }
*ptr++ = arg[j];
}
}
bs <<= 1;
- while (bs && bs--)
+ while (bs && bs--) {
*ptr++ = '\\';
+ }
*ptr++ = '"';
*ptr++ = ' ';
- /* cppcheck-suppress unreadVariable */
+ // cppcheck-suppress unreadVariable
} while ((arg = argv[i++]));
ptr[-1] = '\0';
{
char *path_env;
char *sh = NULL;
- const char *ext;
-
- ext = get_extension(path);
- if (ext && strcasecmp(ext, ".sh") == 0 && (path_env = getenv("PATH")))
+ const char *ext = get_extension(path);
+ if (ext && strcasecmp(ext, ".sh") == 0 && (path_env = getenv("PATH"))) {
sh = find_executable_in_path("sh.exe", NULL, path_env);
+ }
if (!sh && getenv("CCACHE_DETECT_SHEBANG")) {
- /* Detect shebang. */
- FILE *fp;
- fp = fopen(path, "r");
+ // Detect shebang.
+ FILE *fp = fopen(path, "r");
if (fp) {
char buf[10];
fgets(buf, sizeof(buf), fp);
buf[9] = 0;
- if (str_eq(buf, "#!/bin/sh") && (path_env = getenv("PATH")))
+ if (str_eq(buf, "#!/bin/sh") && (path_env = getenv("PATH"))) {
sh = find_executable_in_path("sh.exe", NULL, path_env);
+ }
fclose(fp);
}
}
int fd_stdout, int fd_stderr)
{
PROCESS_INFORMATION pi;
- STARTUPINFO si;
- BOOL ret;
- DWORD exitcode;
- char *sh = NULL;
- char *args;
-
memset(&pi, 0x00, sizeof(pi));
+
+ STARTUPINFO si;
memset(&si, 0x00, sizeof(si));
- sh = win32getshell(path);
- if (sh)
+ char *sh = win32getshell(path);
+ if (sh) {
path = sh;
+ }
si.cb = sizeof(STARTUPINFO);
if (fd_stdout != -1) {
return -1;
}
} else {
- /* redirect subprocess stdout, stderr into current process */
+ // 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);
return -1;
}
}
- args = win32argvtos(sh, argv);
+ char *args = win32argvtos(sh, argv);
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);
+ BOOL 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);
free(args);
if (ret == 0) {
LPVOID lpMsgBuf;
- LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
-
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,
0, NULL);
- lpDisplayBuf =
+ LPVOID lpDisplayBuf =
(LPVOID) LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR) lpMsgBuf)
+ lstrlen((LPCTSTR) __FILE__) + 200)
return -1;
}
WaitForSingleObject(pi.hProcess, INFINITE);
+
+ DWORD exitcode;
GetExitCodeProcess(pi.hProcess, &exitcode);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
- if (!doreturn)
+ if (!doreturn) {
x_exit(exitcode);
+ }
return exitcode;
}
#else
-/* Execute a compiler backend, capturing all output to the given paths the full
- * path to the compiler to run is in argv[0]. */
+// Execute a compiler backend, capturing all output to the given paths the full
+// path to the compiler to run is in argv[0].
int
execute(char **argv, int fd_out, int fd_err, pid_t *pid)
{
- int status;
-
cc_log_argv("Executing ", argv);
block_signals();
}
if (*pid == 0) {
- /* Child. */
+ // Child.
dup2(fd_out, 1);
close(fd_out);
dup2(fd_err, 2);
close(fd_out);
close(fd_err);
+ int status;
if (waitpid(*pid, &status, 0) != *pid) {
fatal("waitpid failed: %s", strerror(errno));
}
}
#endif
-
-/*
- * Find an executable by name in $PATH. Exclude any that are links to
- * exclude_name.
- */
+// Find an executable by name in $PATH. Exclude any that are links to
+// exclude_name.
char *
find_executable(const char *name, const char *exclude_name)
{
- char *path;
-
if (is_absolute_path(name)) {
return x_strdup(name);
}
- path = conf->path;
+ char *path = conf->path;
if (str_eq(path, "")) {
path = getenv("PATH");
}
static char *
find_executable_in_path(const char *name, const char *exclude_name, char *path)
{
- char *tok, *saveptr = NULL;
-
path = x_strdup(path);
- /* search the path looking for the first compiler of the right name
- that isn't us */
- for (tok = strtok_r(path, PATH_DELIM, &saveptr);
+ // Search the path looking for the first compiler of the right name that
+ // isn't us.
+ char *saveptr = NULL;
+ for (char *tok = strtok_r(path, PATH_DELIM, &saveptr);
tok;
tok = strtok_r(NULL, PATH_DELIM, &saveptr)) {
#ifdef _WIN32
char namebuf[MAX_PATH];
- int ret = SearchPath(tok, name, NULL,
- sizeof(namebuf), namebuf, NULL);
+ int ret = SearchPath(tok, name, NULL, sizeof(namebuf), namebuf, NULL);
if (!ret) {
char *exename = format("%s.exe", name);
- ret = SearchPath(tok, exename, NULL,
- sizeof(namebuf), namebuf, NULL);
+ ret = SearchPath(tok, exename, NULL, sizeof(namebuf), namebuf, NULL);
free(exename);
}
(void) exclude_name;
#else
struct stat st1, st2;
char *fname = format("%s/%s", tok, name);
- /* look for a normal executable file */
+ // Look for a normal executable file.
if (access(fname, X_OK) == 0 &&
lstat(fname, &st1) == 0 &&
stat(fname, &st2) == 0 &&
if (buf) {
char *p = basename(buf);
if (str_eq(p, exclude_name)) {
- /* It's a link to "ccache"! */
+ // It's a link to "ccache"!
free(p);
free(buf);
continue;
}
}
- /* Found it! */
+ // Found it!
free(path);
return fname;
}
void
print_command(FILE *fp, char **argv)
{
- int i;
- for (i = 0; argv[i]; i++) {
+ for (int i = 0; argv[i]; i++) {
fprintf(fp, "%s%s", (i == 0) ? "" : " ", argv[i]);
}
fprintf(fp, "\n");
-/*
- * Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
free(p);
}
-/*
- * Initialize exit functions. Must be called once before exitfn_add* are used.
- */
+// Initialize exit functions. Must be called once before exitfn_add* are used.
void
exitfn_init(void)
{
}
}
-/*
- * Add a nullary function to be called when ccache exits. Functions are called
- * in reverse order.
- */
+// Add a nullary function to be called when ccache exits. Functions are called
+// in reverse order.
void
exitfn_add_nullary(void (*function)(void))
{
exitfn_add(call_nullary_exit_function, p);
}
-/*
- * Add a function to be called with a context parameter when ccache exits.
- * Functions are called in reverse order.
- */
+// Add a function to be called with a context parameter when ccache exits.
+// Functions are called in reverse order.
void
exitfn_add(void (*function)(void *), void *context)
{
- struct exit_function *p;
-
- p = x_malloc(sizeof(*p));
+ struct exit_function *p = x_malloc(sizeof(*p));
p->function = function;
p->context = context;
p->next = exit_functions;
exit_functions = p;
}
-/*
- * Call added functions.
- */
+// Call added functions.
void
exitfn_call(void)
{
struct exit_function *p = exit_functions;
exit_functions = NULL;
while (p) {
- struct exit_function *q;
p->function(p->context);
- q = p;
+ struct exit_function *q = p;
p = p->next;
free(q);
}
-/*
- * Copyright (C) 2002 Andrew Tridgell
- * Copyright (C) 2010 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2002 Andrew Tridgell
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
mdfour_update(md, (unsigned char *)s, len);
}
-/* Return the hash result as a hex string. Caller frees. */
+// Return the hash result as a hex string. Caller frees.
char *
hash_result(struct mdfour *md)
{
return format_hash_as_string(sum, (unsigned) md->totalN);
}
-/* return the hash result as 16 binary bytes */
+// Return the hash result as 16 binary bytes.
void
hash_result_as_bytes(struct mdfour *md, unsigned char *out)
{
bool
hash_equal(struct mdfour *md1, struct mdfour *md2)
{
- unsigned char sum1[16], sum2[16];
+ unsigned char sum1[16];
hash_result_as_bytes(md1, sum1);
+ unsigned char sum2[16];
hash_result_as_bytes(md2, sum2);
return memcmp(sum1, sum2, sizeof(sum1)) == 0;
}
-/*
- * Hash some data that is unlikely to occur in the input. The idea is twofold:
- *
- * - Delimit things like arguments from each other (e.g., so that -I -O2 and
- * -I-O2 hash differently).
- * - Tag different types of hashed information so that it's possible to do
- * conditional hashing of information in a safe way (e.g., if we want to hash
- * information X if CCACHE_A is set and information Y if CCACHE_B is set,
- * there should never be a hash collision risk).
- */
+// Hash some data that is unlikely to occur in the input. The idea is twofold:
+//
+// - Delimit things like arguments from each other (e.g., so that -I -O2 and
+// -I-O2 hash differently).
+// - Tag different types of hashed information so that it's possible to do
+// conditional hashing of information in a safe way (e.g., if we want to hash
+// information X if CCACHE_A is set and information Y if CCACHE_B is set,
+// there should never be a hash collision risk).
void
hash_delimiter(struct mdfour *md, const char *type)
{
hash_buffer(md, HASH_DELIMITER, sizeof(HASH_DELIMITER));
- hash_buffer(md, type, strlen(type) + 1); /* Include NUL. */
+ hash_buffer(md, type, strlen(type) + 1); // Include NUL.
}
void
hash_buffer(md, (char *)&x, sizeof(x));
}
-/*
- * Add contents of an open file to the hash. Returns true on success, otherwise
- * false.
- */
+// Add contents of an open file to the hash. Returns true on success, otherwise
+// false.
bool
hash_fd(struct mdfour *md, int fd)
{
- char buf[16384];
+ char buf[READ_BUFFER_SIZE];
ssize_t n;
while ((n = read(fd, buf, sizeof(buf))) != 0) {
return n == 0;
}
-/*
- * Add contents of a file to the hash. Returns true on success, otherwise
- * false.
- */
+// Add contents of a file to the hash. Returns true on success, otherwise
+// false.
bool
hash_file(struct mdfour *md, const char *fname)
{
- int fd;
- bool ret;
-
- fd = open(fname, O_RDONLY|O_BINARY);
+ int fd = open(fname, O_RDONLY|O_BINARY);
if (fd == -1) {
cc_log("Failed to open %s: %s", fname, strerror(errno));
return false;
}
- ret = hash_fd(md, fd);
+ bool ret = hash_fd(md, fd);
close(fd);
return ret;
}
-/*
- * 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
#include "hashutil.h"
&& fh1->size == fh2->size;
}
-/*
- * Search for the strings "__DATE__" and "__TIME__" in str.
- *
- * Returns a bitmask with HASH_SOURCE_CODE_FOUND_DATE and
- * HASH_SOURCE_CODE_FOUND_TIME set appropriately.
- */
+// Search for the strings "__DATE__" and "__TIME__" in str.
+//
+// Returns a bitmask with HASH_SOURCE_CODE_FOUND_DATE and
+// HASH_SOURCE_CODE_FOUND_TIME set appropriately.
int
check_for_temporal_macros(const char *str, size_t len)
{
int result = 0;
- /*
- * We're using the Boyer-Moore-Horspool algorithm, which searches starting
- * from the *end* of the needle. Our needles are 8 characters long, so i
- * starts at 7.
- */
+ // We're using the Boyer-Moore-Horspool algorithm, which searches starting
+ // from the *end* of the needle. Our needles are 8 characters long, so i
+ // starts at 7.
size_t i = 7;
while (i < len) {
- /*
- * Check whether the substring ending at str[i] has the form "__...E__". On
- * the assumption that 'E' is less common in source than '_', we check
- * str[i-2] first.
- */
+ // Check whether the substring ending at str[i] has the form "__...E__". On
+ // the assumption that 'E' is less common in source than '_', we check
+ // str[i-2] first.
if (str[i - 2] == 'E' &&
str[i - 0] == '_' &&
str[i - 7] == '_' &&
str[i - 1] == '_' &&
str[i - 6] == '_') {
- /*
- * Check the remaining characters to see if the substring is "__DATE__"
- * or "__TIME__".
- */
+ // Check the remaining characters to see if the substring is "__DATE__"
+ // or "__TIME__".
if (str[i - 5] == 'D' && str[i - 4] == 'A' &&
str[i - 3] == 'T') {
result |= HASH_SOURCE_CODE_FOUND_DATE;
}
}
- /*
- * macro_skip tells us how far we can skip forward upon seeing str[i] at
- * the end of a substring.
- */
+ // macro_skip tells us how far we can skip forward upon seeing str[i] at
+ // the end of a substring.
i += macro_skip[(uint8_t)str[i]];
}
return result;
}
-/*
- * Hash a string. Returns a bitmask of HASH_SOURCE_CODE_* results.
- */
+// Hash a string. Returns a bitmask of HASH_SOURCE_CODE_* results.
int
hash_source_code_string(
struct conf *conf, struct mdfour *hash, const char *str, size_t len,
{
int result = HASH_SOURCE_CODE_OK;
- /*
- * Check for __DATE__ and __TIME__ if the sloppiness configuration tells us
- * we should.
- */
+ // Check for __DATE__ and __TIME__ if the sloppiness configuration tells us
+ // we should.
if (!(conf->sloppiness & SLOPPY_TIME_MACROS)) {
result |= check_for_temporal_macros(str, len);
}
- /*
- * Hash the source string.
- */
+ // Hash the source string.
hash_buffer(hash, str, len);
if (result & HASH_SOURCE_CODE_FOUND_DATE) {
- /*
- * Make sure that the hash sum changes if the (potential) expansion of
- * __DATE__ changes.
- */
+ // Make sure that the hash sum changes if the (potential) expansion of
+ // __DATE__ changes.
time_t t = time(NULL);
struct tm *now = localtime(&t);
cc_log("Found __DATE__ in %s", path);
hash_buffer(hash, &now->tm_mday, sizeof(now->tm_mday));
}
if (result & HASH_SOURCE_CODE_FOUND_TIME) {
- /*
- * We don't know for sure that the program actually uses the __TIME__
- * macro, but we have to assume it anyway and hash the time stamp. However,
- * that's not very useful since the chance that we get a cache hit later
- * the same second should be quite slim... So, just signal back to the
- * caller that __TIME__ has been found so that the direct mode can be
- * disabled.
- */
+ // We don't know for sure that the program actually uses the __TIME__
+ // macro, but we have to assume it anyway and hash the time stamp. However,
+ // that's not very useful since the chance that we get a cache hit later
+ // the same second should be quite slim... So, just signal back to the
+ // caller that __TIME__ has been found so that the direct mode can be
+ // disabled.
cc_log("Found __TIME__ in %s", path);
}
return result;
}
-/*
- * Hash a file ignoring comments. Returns a bitmask of HASH_SOURCE_CODE_*
- * results.
- */
+// Hash a file ignoring comments. Returns a bitmask of HASH_SOURCE_CODE_*
+// results.
int
hash_source_code_file(struct conf *conf, struct mdfour *hash, const char *path)
{
- char *data;
- size_t size;
-
if (is_precompiled_header(path)) {
if (hash_file(hash, path)) {
return HASH_SOURCE_CODE_OK;
return HASH_SOURCE_CODE_ERROR;
}
} else {
- int result;
-
+ char *data;
+ size_t size;
if (!read_file(path, 0, &data, &size)) {
return HASH_SOURCE_CODE_ERROR;
}
- result = hash_source_code_string(conf, hash, data, size, path);
+ int result = hash_source_code_string(conf, hash, data, size, path);
free(data);
return result;
}
const char *compiler)
{
#ifdef _WIN32
- SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
- HANDLE pipe_out[2];
- PROCESS_INFORMATION pi;
- STARTUPINFO si;
- DWORD exitcode;
- char *sh = NULL;
- char *win32args;
- char *path;
- BOOL ret;
- bool ok;
- int fd;
-#else
- pid_t pid;
- int pipefd[2];
+ // Trim leading space.
+ while (isspace(*command)) {
+ command++;
+ }
+
+ // Add "echo" command.
+ bool cmd;
+ if (str_startswith(command, "echo")) {
+ command = format("cmd.exe /c \"%s\"", command);
+ cmd = true;
+ } else if (str_startswith(command,
+ "%compiler%") && str_eq(compiler, "echo")) {
+ command = format("cmd.exe /c \"%s%s\"", compiler, command + 10);
+ cmd = true;
+ } else {
+ command = x_strdup(command);
+ cmd = false;
+ }
#endif
struct args *args = args_init_from_string(command);
- int i;
- for (i = 0; i < args->argc; i++) {
+ for (int i = 0; i < args->argc; i++) {
if (str_eq(args->argv[i], "%compiler%")) {
args_set(args, i, compiler);
}
cc_log_argv("Executing compiler check command ", args->argv);
#ifdef _WIN32
+ PROCESS_INFORMATION pi;
memset(&pi, 0x00, sizeof(pi));
+ STARTUPINFO si;
memset(&si, 0x00, sizeof(si));
- path = find_executable(args->argv[0], NULL);
- if (!path)
+ char *path = find_executable(args->argv[0], NULL);
+ if (!path) {
path = args->argv[0];
- sh = win32getshell(path);
- if (sh)
+ }
+ char *sh = win32getshell(path);
+ if (sh) {
path = sh;
+ }
si.cb = sizeof(STARTUPINFO);
+
+ HANDLE pipe_out[2];
+ SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
CreatePipe(&pipe_out[0], &pipe_out[1], &sa, 0);
SetHandleInformation(pipe_out[0], HANDLE_FLAG_INHERIT, 0);
si.hStdOutput = pipe_out[1];
si.hStdError = pipe_out[1];
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.dwFlags = STARTF_USESTDHANDLES;
- win32args = win32argvtos(sh, args->argv);
- ret = CreateProcess(path, win32args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
+
+ char *win32args;
+ if (!cmd) {
+ win32args = win32argvtos(sh, args->argv);
+ } else {
+ win32args = (char *)command; // quoted
+ }
+ BOOL ret =
+ CreateProcess(path, win32args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
CloseHandle(pipe_out[1]);
args_free(args);
free(win32args);
+ if (cmd) {
+ free((char *)command); // Original argument was replaced above.
+ }
if (ret == 0) {
stats_update(STATS_COMPCHECK);
return false;
}
- fd = _open_osfhandle((intptr_t) pipe_out[0], O_BINARY);
- ok = hash_fd(hash, fd);
+ int fd = _open_osfhandle((intptr_t) pipe_out[0], O_BINARY);
+ bool ok = hash_fd(hash, fd);
if (!ok) {
cc_log("Error hashing compiler check command output: %s", strerror(errno));
stats_update(STATS_COMPCHECK);
}
WaitForSingleObject(pi.hProcess, INFINITE);
+ DWORD exitcode;
GetExitCodeProcess(pi.hProcess, &exitcode);
CloseHandle(pipe_out[0]);
CloseHandle(pi.hProcess);
}
return ok;
#else
+ int pipefd[2];
if (pipe(pipefd) == -1) {
fatal("pipe failed");
}
- pid = fork();
+
+ pid_t pid = fork();
if (pid == -1) {
fatal("fork failed");
}
if (pid == 0) {
- /* Child. */
+ // Child.
close(pipefd[0]);
close(0);
dup2(pipefd[1], 1);
dup2(pipefd[1], 2);
_exit(execvp(args->argv[0], args->argv));
- return false; /* Never reached. */
+ return false; // Never reached.
} else {
- /* Parent. */
- int status;
- bool ok;
+ // Parent.
args_free(args);
close(pipefd[1]);
- ok = hash_fd(hash, pipefd[0]);
+ bool ok = hash_fd(hash, pipefd[0]);
if (!ok) {
cc_log("Error hashing compiler check command output: %s", strerror(errno));
stats_update(STATS_COMPCHECK);
}
close(pipefd[0]);
+
+ int status;
if (waitpid(pid, &status, 0) != pid) {
cc_log("waitpid failed");
return false;
hash_multicommand_output(struct mdfour *hash, const char *commands,
const char *compiler)
{
- char *command_string, *command, *p, *saveptr = NULL;
+ char *command_string = x_strdup(commands);
+ char *p = command_string;
+ char *command;
+ char *saveptr = NULL;
bool ok = true;
-
- command_string = x_strdup(commands);
- p = command_string;
while ((command = strtok_r(p, ";", &saveptr))) {
if (!hash_command_output(hash, command, compiler)) {
ok = false;
-/*
- * Copyright (C) 2010, 2013 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
-/*
- * Supported file extensions and corresponding languages (as in parameter to
- * the -x option).
- */
+// Supported file extensions and corresponding languages (as in parameter to
+// the -x option).
static const struct {
const char *extension;
const char *language;
{".m", "objective-c"},
{".M", "objective-c++"},
{".mm", "objective-c++"},
- /* Preprocessed: */
+ {".sx", "assembler-with-cpp"},
+ {".S", "assembler-with-cpp"},
+ // Preprocessed:
{".i", "cpp-output"},
{".ii", "c++-cpp-output"},
{".mi", "objective-c-cpp-output"},
{".mii", "objective-c++-cpp-output"},
- /* Header file (for precompilation): */
+ {".s", "assembler"},
+ // Header file (for precompilation):
{".h", "c-header"},
{".H", "c++-header"},
{".h++", "c++-header"},
{".HXX", "c++-header"},
{".tcc", "c++-header"},
{".TCC", "c++-header"},
+ {".cu", "cuda"},
+ {".ic", "cuda-output"},
+ // Fixed form Fortran without preprocessing:
+ {".f", "f77"},
+ {".for", "f77"},
+ {".ftn", "f77"},
+ // Fixed form Fortran with traditional preprocessing:
+ {".F", "f77-cpp-input"},
+ {".FOR", "f77-cpp-input"},
+ {".fpp", "f77-cpp-input"},
+ {".FPP", "f77-cpp-input"},
+ {".FTN", "f77-cpp-input"},
+ // Free form Fortran without preprocessing:
+#if 0 // Could generate modules, ignore for now!
+ {".f90", "f95"},
+ {".f95", "f95"},
+ {".f03", "f95"},
+ {".f08", "f95"},
+#endif
+ // Free form Fortran with traditional preprocessing:
+#if 0 // Could generate modules, ignore for now!
+ {".F90", "f95-cpp-input"},
+ {".F95", "f95-cpp-input"},
+ {".F03", "f95-cpp-input"},
+ {".F08", "f95-cpp-input"},
+#endif
{NULL, NULL}
};
-/*
- * Supported languages and corresponding preprocessed languages.
- */
+// Supported languages and corresponding preprocessed languages.
static const struct {
const char *language;
const char *p_language;
{"objc++-cpp-output", "objective-c++-cpp-output"},
{"objective-c++-header", "objective-c++-cpp-output"},
{"objective-c++-cpp-output", "objective-c++-cpp-output"},
+ {"cuda", "cuda-output"},
+ {"assembler-with-cpp", "assembler"},
+ {"assembler", "assembler"},
+ {"f77-cpp-input", "f77"},
+ {"f77", "f77"},
+#if 0 // Could generate module files, ignore for now!
+ {"f95-cpp-input", "f95"},
+ {"f95", "f95"},
+#endif
{NULL, NULL}
};
-/*
- * Guess the language of a file based on its extension. Returns NULL if the
- * extension is unknown.
- */
+// Guess the language of a file based on its extension. Returns NULL if the
+// extension is unknown.
const char *
language_for_file(const char *fname)
{
- int i;
- const char *p;
-
- p = get_extension(fname);
- for (i = 0; extensions[i].extension; i++) {
+ const char *p = get_extension(fname);
+ for (int i = 0; extensions[i].extension; i++) {
if (str_eq(p, extensions[i].extension)) {
return extensions[i].language;
}
return NULL;
}
-/*
- * Return the preprocessed language for a given language, or NULL if unknown.
- */
+// Return the preprocessed language for a given language, or NULL if unknown.
const char *
p_language_for_language(const char *language)
{
- int i;
-
if (!language) {
return NULL;
}
- for (i = 0; languages[i].language; ++i) {
+ for (int i = 0; languages[i].language; ++i) {
if (str_eq(language, languages[i].language)) {
return languages[i].p_language;
}
return NULL;
}
-/*
- * Return the default file extension (including dot) for a language, or NULL if
- * unknown.
- */
+// Return the default file extension (including dot) for a language, or NULL if
+// unknown.
const char *
extension_for_language(const char *language)
{
- int i;
-
if (!language) {
return NULL;
}
- for (i = 0; extensions[i].extension; i++) {
+ for (int i = 0; extensions[i].extension; i++) {
if (str_eq(language, extensions[i].language)) {
return extensions[i].extension;
}
#ifndef CCACHE_LANGUAGE_H
#define CCACHE_LANGUAGE_H
+#include <stdbool.h>
+
const char *language_for_file(const char *fname);
const char *p_language_for_language(const char *language);
const char *extension_for_language(const char *language);
bool language_is_supported(const char *language);
bool language_is_preprocessed(const char *language);
-#endif /* CCACHE_LANGUAGE_H */
+#endif // CCACHE_LANGUAGE_H
-/*
- * Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
-/*
- * 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
- * will (if possible) break the lock and then try to acquire it again. The
- * staleness limit should be reasonably larger than the longest time the lock
- * can be expected to be held, and the updates of the locked path should
- * probably be made with an atomic rename(2) to avoid corruption in the rare
- * case that the lock is broken by another process.
- */
+// 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
+// will (if possible) break the lock and then try to acquire it again. The
+// staleness limit should be reasonably larger than the longest time the lock
+// can be expected to be held, and the updates of the locked path should
+// probably be made with an atomic rename(2) to avoid corruption in the rare
+// case that the lock is broken by another process.
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;
+ char *my_content = NULL;
+ char *content = NULL;
+ char *initial_content = NULL;
const char *hostname = get_hostname();
bool acquired = false;
-#ifdef _WIN32
- const size_t bufsize = 1024;
- int fd, len;
-#else
- int ret;
-#endif
- unsigned to_sleep = 1000, slept = 0; /* Microseconds. */
+ unsigned to_sleep = 1000; // Microseconds.
+ unsigned slept = 0; // Microseconds.
while (true) {
free(my_content);
my_content = format("%s:%d:%d", hostname, (int)getpid(), (int)time(NULL));
#ifdef _WIN32
- fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0666);
+ int fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0666);
if (fd == -1) {
- saved_errno = errno;
+ int saved_errno = errno;
cc_log("lockfile_acquire: open WRONLY %s: %s", lockfile, strerror(errno));
if (saved_errno == ENOENT) {
- /* Directory doesn't exist? */
+ // Directory doesn't exist?
if (create_parent_dirs(lockfile) == 0) {
- /* OK. Retry. */
+ // OK. Retry.
continue;
}
}
if (saved_errno != EEXIST) {
- /* Directory doesn't exist or isn't writable? */
+ // Directory doesn't exist or isn't writable?
goto out;
}
- /* Someone else has the lock. */
+ // 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.
- */
+ // The file was removed after the open() call above, so retry
+ // acquiring it.
continue;
} else {
cc_log("lockfile_acquire: open RDONLY %s: %s",
}
}
free(content);
+ const size_t bufsize = 1024;
content = x_malloc(bufsize);
- if ((len = read(fd, content, bufsize - 1)) == -1) {
+ 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. */
+ // 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);
goto out;
}
#else
- ret = symlink(my_content, lockfile);
- if (ret == 0) {
- /* We got the lock. */
+ if (symlink(my_content, lockfile) == 0) {
+ // We got the lock.
acquired = true;
goto out;
}
- saved_errno = errno;
+ int saved_errno = errno;
cc_log("lockfile_acquire: symlink %s: %s", lockfile, strerror(saved_errno));
if (saved_errno == ENOENT) {
- /* Directory doesn't exist? */
+ // Directory doesn't exist?
if (create_parent_dirs(lockfile) == 0) {
- /* OK. Retry. */
+ // OK. Retry.
continue;
}
}
if (saved_errno == EPERM) {
- /*
- * The file system does not support symbolic links. We have no choice but
- * to grant the lock anyway.
- */
+ // The file system does not support symbolic links. We have no choice but
+ // to grant the lock anyway.
acquired = true;
goto out;
}
if (saved_errno != EEXIST) {
- /* Directory doesn't exist or isn't writable? */
+ // Directory doesn't exist or isn't writable?
goto out;
}
free(content);
content = x_readlink(lockfile);
- /* cppcheck-suppress nullPointer - false positive */
+ // cppcheck-suppress nullPointer - false positive
if (!content) {
if (errno == ENOENT) {
- /*
- * The symlink was removed after the symlink() call above, so retry
- * acquiring it.
- */
+ // The symlink was removed after the symlink() call above, so retry
+ // acquiring it.
continue;
} else {
cc_log("lockfile_acquire: readlink %s: %s", lockfile, strerror(errno));
#endif
if (str_eq(content, my_content)) {
- /* Lost NFS reply? */
+ // Lost NFS reply?
cc_log("lockfile_acquire: symlink %s failed but we got the lock anyway",
lockfile);
acquired = true;
goto out;
}
- /*
- * A possible improvement here would be to check if the process holding the
- * lock is still alive and break the lock early if it isn't.
- */
+ // A possible improvement here would be to check if the process holding the
+ // lock is still alive and break the lock early if it isn't.
cc_log("lockfile_acquire: lock info for %s: %s", lockfile, content);
if (!initial_content) {
initial_content = x_strdup(content);
}
if (slept > staleness_limit) {
if (str_eq(content, initial_content)) {
- /* The lock seems to be stale -- break it. */
+ // The lock seems to be stale -- break it.
cc_log("lockfile_acquire: breaking %s", lockfile);
+ // Try to acquire path.lock.lock:
if (lockfile_acquire(lockfile, staleness_limit)) {
- lockfile_release(path);
- lockfile_release(lockfile);
+ lockfile_release(path); // Remove path.lock
+ lockfile_release(lockfile); // Remove path.lock.lock
to_sleep = 1000;
slept = 0;
continue;
return acquired;
}
-/*
- * Release the lockfile for the given path. Assumes that we are the legitimate
- * owner.
- */
+// Release the lockfile for the given path. Assumes that we are the legitimate
+// owner.
void
lockfile_release(const char *path)
{
-/*
- * A Boyer-Moore-Horspool skip table used for searching for the strings
- * "__TIME__" and "__DATE__".
- *
- * macro_skip[c] = 8 for all c not in "__TIME__" and "__DATE__".
- *
- * The other characters map as follows:
- *
- * _ -> 1
- * A -> 4
- * D -> 5
- * E -> 2
- * I -> 4
- * M -> 3
- * T -> 3
- *
- *
- * This was generated with the following Python script:
- *
- * m = {'_': 1,
- * 'A': 4,
- * 'D': 5,
- * 'E': 2,
- * 'I': 4,
- * 'M': 3,
- * 'T': 3}
- *
- * for i in range(0, 256):
- * if chr(i) in m:
- * num = m[chr(i)]
- * else:
- * num = 8
- * print ("%d, " % num),
- *
- * if i % 16 == 15:
- * print ""
- */
+#ifndef CCACHE_MACROSKIP_H
+#define CCACHE_MACROSKIP_H
+
+#include <stdint.h>
+
+// A Boyer-Moore-Horspool skip table used for searching for the strings
+// "__TIME__" and "__DATE__".
+//
+// macro_skip[c] = 8 for all c not in "__TIME__" and "__DATE__".
+//
+// The other characters map as follows:
+//
+// _ -> 1
+// A -> 4
+// D -> 5
+// E -> 2
+// I -> 4
+// M -> 3
+// T -> 3
+//
+//
+// This was generated with the following Python script:
+//
+// m = {'_': 1,
+// 'A': 4,
+// 'D': 5,
+// 'E': 2,
+// 'I': 4,
+// 'M': 3,
+// 'T': 3}
+//
+// for i in range(0, 256):
+// if chr(i) in m:
+// num = m[chr(i)]
+// else:
+// num = 8
+// print ("%d, " % num),
+//
+// if i % 16 == 15:
+// print ""
static const uint32_t macro_skip[] = {
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
};
+
+#endif
-/*
- * ccache -- a fast C/C++ compiler cache
- *
- * Copyright (C) 2010 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// ccache -- a fast C/C++ compiler cache
+//
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
int
ccache_main(int argc, char *argv[]);
-/*
- * Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
#include "hashtable_itr.h"
#include <zlib.h>
-/*
- * Sketchy specification of the manifest disk format:
- *
- * <magic> magic number (4 bytes)
- * <version> file format version (1 byte unsigned int)
- * <hash_size> size of the hash fields (in bytes) (1 byte unsigned int)
- * <reserved> reserved for future use (2 bytes)
- * ----------------------------------------------------------------------------
- * <n> number of include file paths (4 bytes unsigned int)
- * <path_0> path to include file (NUL-terminated string,
- * ... at most 1024 bytes)
- * <path_n-1>
- * ----------------------------------------------------------------------------
- * <n> number of include file hash entries (4 bytes unsigned int)
- * <index[0]> index of include file path (4 bytes unsigned int)
- * <hash[0]> hash of include file (<hash_size> bytes)
- * <size[0]> size of include file (4 bytes unsigned int)
- * <mtime[0]> mtime of include file (8 bytes signed int)
- * <ctime[0]> ctime of include file (8 bytes signed int)
- * ...
- * <index[n-1]>
- * <hash[n-1]>
- * <size[n-1]>
- * <mtime[n-1]>
- * <ctime[n-1]>
- * ----------------------------------------------------------------------------
- * <n> number of object name entries (4 bytes unsigned int)
- * <m[0]> number of include file hash indexes (4 bytes unsigned int)
- * <index[0][0]> include file hash index (4 bytes unsigned int)
- * ...
- * <index[0][m[0]-1]>
- * <hash[0]> hash part of object name (<hash_size> bytes)
- * <size[0]> size part of object name (4 bytes unsigned int)
- * ...
- * <m[n-1]> number of include file hash indexes
- * <index[n-1][0]> include file hash index
- * ...
- * <index[n-1][m[n-1]]>
- * <hash[n-1]>
- * <size[n-1]>
- */
+// Sketchy specification of the manifest disk format:
+//
+// <magic> magic number (4 bytes)
+// <version> file format version (1 byte unsigned int)
+// <hash_size> size of the hash fields (in bytes) (1 byte unsigned int)
+// <reserved> reserved for future use (2 bytes)
+// ----------------------------------------------------------------------------
+// <n> number of include file paths (4 bytes unsigned int)
+// <path_0> path to include file (NUL-terminated string,
+// ... at most 1024 bytes)
+// <path_n-1>
+// ----------------------------------------------------------------------------
+// <n> number of include file hash entries (4 bytes unsigned int)
+// <index[0]> index of include file path (4 bytes unsigned int)
+// <hash[0]> hash of include file (<hash_size> bytes)
+// <size[0]> size of include file (4 bytes unsigned int)
+// <mtime[0]> mtime of include file (8 bytes signed int)
+// <ctime[0]> ctime of include file (8 bytes signed int)
+// ...
+// <index[n-1]>
+// <hash[n-1]>
+// <size[n-1]>
+// <mtime[n-1]>
+// <ctime[n-1]>
+// ----------------------------------------------------------------------------
+// <n> number of object name entries (4 bytes unsigned int)
+// <m[0]> number of include file hash indexes (4 bytes unsigned int)
+// <index[0][0]> include file hash index (4 bytes unsigned int)
+// ...
+// <index[0][m[0]-1]>
+// <hash[0]> hash part of object name (<hash_size> bytes)
+// <size[0]> size part of object name (4 bytes unsigned int)
+// ...
+// <m[n-1]> number of include file hash indexes
+// <index[n-1][0]> include file hash index
+// ...
+// <index[n-1][m[n-1]]>
+// <hash[n-1]>
+// <size[n-1]>
static const uint32_t MAGIC = 0x63436d46U;
static const uint32_t MAX_MANIFEST_ENTRIES = 100;
do { enum { ccache_static_assert__ = 1/(e) }; } while (false)
struct file_info {
- /* Index to n_files. */
+ // Index to n_files.
uint32_t index;
- /* Hash of referenced file. */
+ // Hash of referenced file.
uint8_t hash[16];
- /* Size of referenced file. */
+ // Size of referenced file.
uint32_t size;
- /* mtime of referenced file. */
+ // mtime of referenced file.
int64_t mtime;
- /* ctime of referenced file. */
+ // ctime of referenced file.
int64_t ctime;
};
struct object {
- /* Number of entries in file_info_indexes. */
+ // Number of entries in file_info_indexes.
uint32_t n_file_info_indexes;
- /* Indexes to file_infos. */
+ // Indexes to file_infos.
uint32_t *file_info_indexes;
- /* Hash of the object itself. */
+ // Hash of the object itself.
struct file_hash hash;
};
struct manifest {
- /* Version of decoded file. */
+ // Version of decoded file.
uint8_t version;
- /* Reserved for future use. */
+ // Reserved for future use.
uint16_t reserved;
- /* Size of hash fields (in bytes). */
+ // Size of hash fields (in bytes).
uint8_t hash_size;
- /* Referenced include files. */
+ // Referenced include files.
uint32_t n_files;
char **files;
- /* Information about referenced include files. */
+ // Information about referenced include files.
uint32_t n_file_infos;
struct file_info *file_infos;
- /* Object names plus references to include file hashes. */
+ // Object names plus references to include file hashes.
uint32_t n_objects;
struct object *objects;
};
static unsigned int
hash_from_file_info(void *key)
{
- ccache_static_assert(sizeof(struct file_info) == 40); /* No padding. */
+ ccache_static_assert(sizeof(struct file_info) == 40); // No padding.
return murmurhashneutral2(key, sizeof(struct file_info), 0);
}
static void
free_manifest(struct manifest *mf)
{
- uint32_t i;
- for (i = 0; i < mf->n_files; i++) {
+ for (uint32_t i = 0; i < mf->n_files; i++) {
free(mf->files[i]);
}
free(mf->files);
free(mf->file_infos);
- for (i = 0; i < mf->n_objects; i++) {
+ for (uint32_t i = 0; i < mf->n_objects; i++) {
free(mf->objects[i].file_info_indexes);
}
free(mf->objects);
#define READ_BYTE(var) \
do { \
- int ch_; \
- ch_ = gzgetc(f); \
+ int ch_ = gzgetc(f); \
if (ch_ == EOF) { \
goto error; \
} \
#define READ_INT(size, var) \
do { \
- int ch_; \
- size_t i_; \
(var) = 0; \
- for (i_ = 0; i_ < (size); i_++) { \
- ch_ = gzgetc(f); \
+ for (size_t i_ = 0; i_ < (size); i_++) { \
+ int ch_ = gzgetc(f); \
if (ch_ == EOF) { \
goto error; \
} \
do { \
char buf_[1024]; \
size_t i_; \
- int ch_; \
for (i_ = 0; i_ < sizeof(buf_); i_++) { \
- ch_ = gzgetc(f); \
+ int ch_ = gzgetc(f); \
if (ch_ == EOF) { \
goto error; \
} \
#define READ_BYTES(n, var) \
do { \
- size_t i_; \
- int ch_; \
- for (i_ = 0; i_ < (n); i_++) { \
- ch_ = gzgetc(f); \
+ for (size_t i_ = 0; i_ < (n); i_++) { \
+ int ch_ = gzgetc(f); \
if (ch_ == EOF) { \
goto error; \
} \
static struct manifest *
create_empty_manifest(void)
{
- struct manifest *mf;
-
- mf = x_malloc(sizeof(*mf));
+ struct manifest *mf = x_malloc(sizeof(*mf));
mf->hash_size = 16;
mf->n_files = 0;
mf->files = NULL;
static struct manifest *
read_manifest(gzFile f)
{
- struct manifest *mf;
- uint32_t i, j;
- uint32_t magic;
-
- mf = create_empty_manifest();
+ struct manifest *mf = create_empty_manifest();
+ uint32_t magic;
READ_INT(4, magic);
if (magic != MAGIC) {
cc_log("Manifest file has bad magic number %u", magic);
- free_manifest(mf);
- return NULL;
+ goto error;
}
+
READ_BYTE(mf->version);
if (mf->version != MANIFEST_VERSION) {
cc_log("Manifest file has unknown version %u", mf->version);
- free_manifest(mf);
- return NULL;
+ goto error;
}
READ_BYTE(mf->hash_size);
if (mf->hash_size != 16) {
- /* Temporary measure until we support different hash algorithms. */
+ // Temporary measure until we support different hash algorithms.
cc_log("Manifest file has unsupported hash size %u", mf->hash_size);
- free_manifest(mf);
- return NULL;
+ goto error;
}
READ_INT(2, mf->reserved);
READ_INT(4, mf->n_files);
mf->files = x_calloc(mf->n_files, sizeof(*mf->files));
- for (i = 0; i < mf->n_files; i++) {
+ for (uint32_t i = 0; i < mf->n_files; i++) {
READ_STR(mf->files[i]);
}
READ_INT(4, mf->n_file_infos);
mf->file_infos = x_calloc(mf->n_file_infos, sizeof(*mf->file_infos));
- for (i = 0; i < mf->n_file_infos; i++) {
+ for (uint32_t i = 0; i < mf->n_file_infos; i++) {
READ_INT(4, mf->file_infos[i].index);
READ_BYTES(mf->hash_size, mf->file_infos[i].hash);
READ_INT(4, mf->file_infos[i].size);
READ_INT(4, mf->n_objects);
mf->objects = x_calloc(mf->n_objects, sizeof(*mf->objects));
- for (i = 0; i < mf->n_objects; i++) {
+ for (uint32_t i = 0; i < mf->n_objects; i++) {
READ_INT(4, mf->objects[i].n_file_info_indexes);
mf->objects[i].file_info_indexes =
x_calloc(mf->objects[i].n_file_info_indexes,
sizeof(*mf->objects[i].file_info_indexes));
- for (j = 0; j < mf->objects[i].n_file_info_indexes; j++) {
+ for (uint32_t j = 0; j < mf->objects[i].n_file_info_indexes; j++) {
READ_INT(4, mf->objects[i].file_info_indexes[j]);
}
READ_BYTES(mf->hash_size, mf->objects[i].hash.hash);
static int
write_manifest(gzFile f, const struct manifest *mf)
{
- uint32_t i, j;
-
WRITE_INT(4, MAGIC);
WRITE_INT(1, MANIFEST_VERSION);
WRITE_INT(1, 16);
WRITE_INT(2, 0);
WRITE_INT(4, mf->n_files);
- for (i = 0; i < mf->n_files; i++) {
+ for (uint32_t i = 0; i < mf->n_files; i++) {
WRITE_STR(mf->files[i]);
}
WRITE_INT(4, mf->n_file_infos);
- for (i = 0; i < mf->n_file_infos; i++) {
+ for (uint32_t i = 0; i < mf->n_file_infos; i++) {
WRITE_INT(4, mf->file_infos[i].index);
WRITE_BYTES(mf->hash_size, mf->file_infos[i].hash);
WRITE_INT(4, mf->file_infos[i].size);
}
WRITE_INT(4, mf->n_objects);
- for (i = 0; i < mf->n_objects; i++) {
+ for (uint32_t i = 0; i < mf->n_objects; i++) {
WRITE_INT(4, mf->objects[i].n_file_info_indexes);
- for (j = 0; j < mf->objects[i].n_file_info_indexes; j++) {
+ for (uint32_t j = 0; j < mf->objects[i].n_file_info_indexes; j++) {
WRITE_INT(4, mf->objects[i].file_info_indexes[j]);
}
WRITE_BYTES(mf->hash_size, mf->objects[i].hash.hash);
verify_object(struct conf *conf, struct manifest *mf, struct object *obj,
struct hashtable *stated_files, struct hashtable *hashed_files)
{
- uint32_t i;
- struct file_hash *actual;
- struct mdfour hash;
- int result;
-
- for (i = 0; i < obj->n_file_info_indexes; i++) {
+ for (uint32_t i = 0; i < obj->n_file_info_indexes; i++) {
struct file_info *fi = &mf->file_infos[obj->file_info_indexes[i]];
char *path = mf->files[fi->index];
struct file_stats *st = hashtable_search(stated_files, path);
}
if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) {
- /*
- * st->ctime is sometimes 0, so we can't check that both st->ctime and
- * st->mtime are greater than time_of_compilation. But it's sufficient to
- * check that either is.
- */
+ // st->ctime is sometimes 0, so we can't check that both st->ctime and
+ // st->mtime are greater than time_of_compilation. But it's sufficient to
+ // check that either is.
if (fi->size == st->size
&& fi->mtime == st->mtime
&& fi->ctime == st->ctime
}
}
- actual = hashtable_search(hashed_files, path);
+ struct file_hash *actual = hashtable_search(hashed_files, path);
if (!actual) {
- actual = x_malloc(sizeof(*actual));
+ struct mdfour hash;
hash_start(&hash);
- result = hash_source_code_file(conf, &hash, path);
+ int result = hash_source_code_file(conf, &hash, path);
if (result & HASH_SOURCE_CODE_ERROR) {
cc_log("Failed hashing %s", path);
- free(actual);
return 0;
}
if (result & HASH_SOURCE_CODE_FOUND_TIME) {
- free(actual);
return 0;
}
+ actual = x_malloc(sizeof(*actual));
hash_result_as_bytes(&hash, actual->hash);
actual->size = hash.totalN;
hashtable_insert(hashed_files, x_strdup(path), actual);
static struct hashtable *
create_string_index_map(char **strings, uint32_t len)
{
- uint32_t i;
- struct hashtable *h;
- uint32_t *index;
-
- h = create_hashtable(1000, hash_from_string, strings_equal);
- for (i = 0; i < len; i++) {
- index = x_malloc(sizeof(*index));
+ struct hashtable *h =
+ create_hashtable(1000, hash_from_string, strings_equal);
+ for (uint32_t i = 0; i < len; i++) {
+ uint32_t *index = x_malloc(sizeof(*index));
*index = i;
hashtable_insert(h, x_strdup(strings[i]), index);
}
static struct hashtable *
create_file_info_index_map(struct file_info *infos, uint32_t len)
{
- uint32_t i;
- struct hashtable *h;
- struct file_info *fi;
- uint32_t *index;
-
- h = create_hashtable(1000, hash_from_file_info, file_infos_equal);
- for (i = 0; i < len; i++) {
- fi = x_malloc(sizeof(*fi));
+ struct hashtable *h =
+ create_hashtable(1000, hash_from_file_info, file_infos_equal);
+ for (uint32_t i = 0; i < len; i++) {
+ struct file_info *fi = x_malloc(sizeof(*fi));
*fi = infos[i];
- index = x_malloc(sizeof(*index));
+ uint32_t *index = x_malloc(sizeof(*index));
*index = i;
hashtable_insert(h, fi, index);
}
get_include_file_index(struct manifest *mf, char *path,
struct hashtable *mf_files)
{
- uint32_t *index;
- uint32_t n;
-
- index = hashtable_search(mf_files, path);
+ uint32_t *index = hashtable_search(mf_files, path);
if (index) {
return *index;
}
- n = mf->n_files;
+ uint32_t n = mf->n_files;
mf->files = x_realloc(mf->files, (n + 1) * sizeof(*mf->files));
mf->n_files++;
mf->files[n] = x_strdup(path);
-
return n;
}
struct hashtable *mf_file_infos)
{
struct file_info fi;
- uint32_t *fi_index;
- uint32_t n;
- struct stat file_stat;
-
fi.index = get_include_file_index(mf, path, mf_files);
memcpy(fi.hash, file_hash->hash, sizeof(fi.hash));
fi.size = file_hash->size;
- /*
- * file_stat.st_{m,c}time has a resolution of 1 second, so we can cache the
- * file's mtime and ctime only if they're at least one second older than
- * time_of_compilation.
- *
- * st->ctime may be 0, so we have to check time_of_compilation against
- * MAX(mtime, ctime).
- */
+ // file_stat.st_{m,c}time has a resolution of 1 second, so we can cache the
+ // file's mtime and ctime only if they're at least one second older than
+ // time_of_compilation.
+ //
+ // st->ctime may be 0, so we have to check time_of_compilation against
+ // MAX(mtime, ctime).
+ struct stat file_stat;
if (stat(path, &file_stat) != -1
&& time_of_compilation > MAX(file_stat.st_mtime, file_stat.st_ctime)) {
fi.mtime = file_stat.st_mtime;
fi.ctime = -1;
}
- fi_index = hashtable_search(mf_file_infos, &fi);
+ uint32_t *fi_index = hashtable_search(mf_file_infos, &fi);
if (fi_index) {
return *fi_index;
}
- n = mf->n_file_infos;
+ uint32_t n = mf->n_file_infos;
mf->file_infos = x_realloc(mf->file_infos, (n + 1) * sizeof(*mf->file_infos));
mf->n_file_infos++;
mf->file_infos[n] = fi;
-
return n;
}
add_file_info_indexes(uint32_t *indexes, uint32_t size,
struct manifest *mf, struct hashtable *included_files)
{
- struct hashtable_itr *iter;
- uint32_t i;
- struct hashtable *mf_files; /* path --> index */
- struct hashtable *mf_file_infos; /* struct file_info --> index */
-
if (size == 0) {
return;
}
- mf_files = create_string_index_map(mf->files, mf->n_files);
- mf_file_infos = create_file_info_index_map(mf->file_infos, mf->n_file_infos);
- iter = hashtable_iterator(included_files);
- i = 0;
+ // path --> index
+ struct hashtable *mf_files =
+ create_string_index_map(mf->files, mf->n_files);
+ // struct file_info --> index
+ struct hashtable *mf_file_infos =
+ create_file_info_index_map(mf->file_infos, mf->n_file_infos);
+ struct hashtable_itr *iter = hashtable_iterator(included_files);
+ uint32_t i = 0;
do {
char *path = hashtable_iterator_key(iter);
struct file_hash *file_hash = hashtable_iterator_value(iter);
struct file_hash *object_hash,
struct hashtable *included_files)
{
- struct object *obj;
- uint32_t n;
-
- n = mf->n_objects;
- mf->objects = x_realloc(mf->objects, (n + 1) * sizeof(*mf->objects));
+ uint32_t n_objs = mf->n_objects;
+ mf->objects = x_realloc(mf->objects, (n_objs + 1) * sizeof(*mf->objects));
mf->n_objects++;
- obj = &mf->objects[n];
+ struct object *obj = &mf->objects[n_objs];
- n = hashtable_count(included_files);
- obj->n_file_info_indexes = n;
- obj->file_info_indexes = x_malloc(n * sizeof(*obj->file_info_indexes));
- add_file_info_indexes(obj->file_info_indexes, n, mf, included_files);
+ uint32_t n_fii = hashtable_count(included_files);
+ obj->n_file_info_indexes = n_fii;
+ obj->file_info_indexes = x_malloc(n_fii * sizeof(*obj->file_info_indexes));
+ add_file_info_indexes(obj->file_info_indexes, n_fii, mf, included_files);
memcpy(obj->hash.hash, object_hash->hash, mf->hash_size);
obj->hash.size = object_hash->size;
}
-/*
- * Try to get the object hash from a manifest file. Caller frees. Returns NULL
- * on failure.
- */
+// Try to get the object hash from a manifest file. Caller frees. Returns NULL
+// on failure.
struct file_hash *
manifest_get(struct conf *conf, const char *manifest_path)
{
- int fd;
gzFile f = NULL;
struct manifest *mf = NULL;
- struct hashtable *hashed_files = NULL; /* path --> struct file_hash */
- struct hashtable *stated_files = NULL; /* path --> struct file_stats */
- uint32_t i;
+ struct hashtable *hashed_files = NULL; // path --> struct file_hash
+ struct hashtable *stated_files = NULL; // path --> struct file_stats
struct file_hash *fh = NULL;
- fd = open(manifest_path, O_RDONLY | O_BINARY);
+ int fd = open(manifest_path, O_RDONLY | O_BINARY);
if (fd == -1) {
- /* Cache miss. */
+ // Cache miss.
cc_log("No such manifest file");
goto out;
}
hashed_files = create_hashtable(1000, hash_from_string, strings_equal);
stated_files = create_hashtable(1000, hash_from_string, strings_equal);
- /* Check newest object first since it's a bit more likely to match. */
- for (i = mf->n_objects; i > 0; i--) {
+ // Check newest object first since it's a bit more likely to match.
+ for (uint32_t i = mf->n_objects; i > 0; i--) {
if (verify_object(conf, mf, &mf->objects[i - 1],
stated_files, hashed_files)) {
fh = x_malloc(sizeof(*fh));
return fh;
}
-/*
- * Put the object name into a manifest file given a set of included files.
- * Returns true on success, otherwise false.
- */
+// Put the object name into a manifest file given a set of included files.
+// Returns true on success, otherwise false.
bool
manifest_put(const char *manifest_path, struct file_hash *object_hash,
struct hashtable *included_files)
{
int ret = 0;
- int fd1;
- int fd2;
gzFile f2 = NULL;
struct manifest *mf = NULL;
char *tmp_file = NULL;
- /*
- * We don't bother to acquire a lock when writing the manifest to disk. A
- * race between two processes will only result in one lost entry, which is
- * not a big deal, and it's also very unlikely.
- */
+ // We don't bother to acquire a lock when writing the manifest to disk. A
+ // race between two processes will only result in one lost entry, which is
+ // not a big deal, and it's also very unlikely.
- fd1 = open(manifest_path, O_RDONLY | O_BINARY);
+ int fd1 = open(manifest_path, O_RDONLY | O_BINARY);
if (fd1 == -1) {
- /* New file. */
+ // New file.
mf = create_empty_manifest();
} else {
gzFile f1 = gzdopen(fd1, "rb");
}
if (mf->n_objects > MAX_MANIFEST_ENTRIES) {
- /*
- * Normally, there shouldn't be many object entries in the manifest since
- * new entries are added only if an include file has changed but not the
- * source file, and you typically change source files more often than
- * header files. However, it's certainly possible to imagine cases where
- * the manifest will grow large (for instance, a generated header file that
- * changes for every build), and this must be taken care of since
- * processing an ever growing manifest eventually will take too much time.
- * A good way of solving this would be to maintain the object entries in
- * LRU order and discarding the old ones. An easy way is to throw away all
- * entries when there are too many. Let's do that for now.
- */
+ // Normally, there shouldn't be many object entries in the manifest since
+ // new entries are added only if an include file has changed but not the
+ // source file, and you typically change source files more often than
+ // header files. However, it's certainly possible to imagine cases where
+ // the manifest will grow large (for instance, a generated header file that
+ // changes for every build), and this must be taken care of since
+ // processing an ever growing manifest eventually will take too much time.
+ // A good way of solving this would be to maintain the object entries in
+ // LRU order and discarding the old ones. An easy way is to throw away all
+ // entries when there are too many. Let's do that for now.
cc_log("More than %u entries in manifest file; discarding",
MAX_MANIFEST_ENTRIES);
free_manifest(mf);
mf = create_empty_manifest();
} else if (mf->n_file_infos > MAX_MANIFEST_FILE_INFO_ENTRIES) {
- /* Rarely, file_info entries can grow large in pathological cases where
- * many included files change, but the main file does not. This also puts
- * an upper bound on the number of file_info entries.
- */
+ // Rarely, file_info entries can grow large in pathological cases where
+ // many included files change, but the main file does not. This also puts
+ // an upper bound on the number of file_info entries.
cc_log("More than %u file_info entries in manifest file; discarding",
MAX_MANIFEST_FILE_INFO_ENTRIES);
free_manifest(mf);
}
tmp_file = format("%s.tmp", manifest_path);
- fd2 = create_tmp_fd(&tmp_file);
+ int fd2 = create_tmp_fd(&tmp_file);
f2 = gzdopen(fd2, "wb");
if (!f2) {
cc_log("Failed to gzdopen %s", tmp_file);
manifest_dump(const char *manifest_path, FILE *stream)
{
struct manifest *mf = NULL;
- int fd;
gzFile f = NULL;
bool ret = false;
- unsigned i, j;
- fd = open(manifest_path, O_RDONLY | O_BINARY);
+ int fd = open(manifest_path, O_RDONLY | O_BINARY);
if (fd == -1) {
fprintf(stderr, "No such manifest file: %s\n", manifest_path);
goto out;
fprintf(stream, "Hash size: %u\n", (unsigned)mf->hash_size);
fprintf(stream, "Reserved field: %u\n", (unsigned)mf->reserved);
fprintf(stream, "File paths (%u):\n", (unsigned)mf->n_files);
- for (i = 0; i < mf->n_files; ++i) {
+ for (unsigned i = 0; i < mf->n_files; ++i) {
fprintf(stream, " %u: %s\n", i, mf->files[i]);
}
fprintf(stream, "File infos (%u):\n", (unsigned)mf->n_file_infos);
- for (i = 0; i < mf->n_file_infos; ++i) {
+ for (unsigned i = 0; i < mf->n_file_infos; ++i) {
char *hash;
fprintf(stream, " %u:\n", i);
fprintf(stream, " Path index: %u\n", mf->file_infos[i].index);
fprintf(stream, " Ctime: %lld\n", (long long)mf->file_infos[i].ctime);
}
fprintf(stream, "Results (%u):\n", (unsigned)mf->n_objects);
- for (i = 0; i < mf->n_objects; ++i) {
+ for (unsigned i = 0; i < mf->n_objects; ++i) {
char *hash;
fprintf(stream, " %u:\n", i);
fprintf(stream, " File info indexes:");
- for (j = 0; j < mf->objects[i].n_file_info_indexes; ++j) {
+ for (unsigned j = 0; j < mf->objects[i].n_file_info_indexes; ++j) {
fprintf(stream, " %u", mf->objects[i].file_info_indexes[j]);
}
fprintf(stream, "\n");
-/*
- * Copyright (C) 1997-1998 Andrew Tridgell
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 1997-1998 Andrew Tridgell
+// Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
-/* NOTE: This code makes no attempt to be fast! */
+// NOTE: This code makes no attempt to be fast!
static struct mdfour *m;
#define ROUND3(a, b, c, d, k, s) \
a = lshift((a + H(b, c, d) + M[k] + 0x6ED9EBA1)&MASK32, s)
-/* this applies md4 to 64 byte chunks */
+// This applies md4 to 64 byte chunks.
static void
mdfour64(uint32_t *M)
{
uint32_t AA, BB, CC, DD;
uint32_t A, B, C, D;
- A = m->A; B = m->B; C = m->C; D = m->D;
- AA = A; BB = B; CC = C; DD = D;
+ A = m->A;
+ B = m->B;
+ C = m->C;
+ D = m->D;
+ AA = A;
+ BB = B;
+ CC = C;
+ DD = D;
ROUND1(A, B, C, D, 0, 3); ROUND1(D, A, B, C, 1, 7);
ROUND1(C, D, A, B, 2, 11); ROUND1(B, C, D, A, 3, 19);
ROUND3(A, B, C, D, 3, 3); ROUND3(D, A, B, C, 11, 9);
ROUND3(C, D, A, B, 7, 11); ROUND3(B, C, D, A, 15, 15);
- A += AA; B += BB;
- C += CC; D += DD;
+ A += AA;
+ B += BB;
+ C += CC;
+ D += DD;
- A &= MASK32; B &= MASK32;
- C &= MASK32; D &= MASK32;
+ A &= MASK32;
+ B &= MASK32;
+ C &= MASK32;
+ D &= MASK32;
- m->A = A; m->B = B; m->C = C; m->D = D;
+ m->A = A;
+ m->B = B;
+ m->C = C;
+ m->D = D;
}
static void
copy64(uint32_t *M, const unsigned char *in)
{
#ifdef WORDS_BIGENDIAN
- int i;
-
- for (i = 0; i < 16; i++)
+ for (int i = 0; i < 16; i++) {
M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
(in[i*4+1]<<8) | (in[i*4+0]<<0);
+ }
#else
memcpy(M, in, 16*4);
#endif
static
void mdfour_tail(const unsigned char *in, size_t n)
{
+ m->totalN += n;
+ uint32_t b = m->totalN * 8;
unsigned char buf[128] = { 0 };
uint32_t M[16];
- uint32_t b;
-
- m->totalN += n;
-
- b = m->totalN * 8;
-
if (n) {
memcpy(buf, in, n);
}
void
mdfour_update(struct mdfour *md, const unsigned char *in, size_t n)
{
- uint32_t M[16];
-
#ifdef CCACHE_DEBUG_HASH
if (getenv("CCACHE_DEBUG_HASH")) {
FILE *f = fopen("ccache-debug-hash.bin", "a");
return;
}
+ uint32_t M[16];
if (md->tail_len) {
size_t len = 64 - md->tail_len;
if (len > n) {
-/*
- * MurmurHashNeutral2, by Austin Appleby. Released to the public domain. See
- * <http://murmurhash.googlepages.com>.
- */
+// MurmurHashNeutral2, by Austin Appleby. Released to the public domain. See
+// <http://murmurhash.googlepages.com>.
#include "murmurhashneutral2.h"
{
const unsigned int m = 0x5bd1e995;
const int r = 24;
-
unsigned int h = seed ^ len;
-
const unsigned char *data = (const unsigned char *)key;
while (len >= 4) {
- unsigned int k;
-
- k = data[0];
+ unsigned int k = data[0];
k |= data[1] << 8;
k |= data[2] << 16;
k |= data[3] << 24;
static UINTMAX_T myround(LDOUBLE);
static LDOUBLE mypow10(int);
+#ifndef __MINGW32__
extern int errno;
+#endif
int
rpl_vsnprintf(char *str, size_t size, const char *format, va_list args)
-/*
- * Copyright (C) 2002-2004 Andrew Tridgell
- * Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * Routines to handle the stats files. The stats file is stored one per cache
- * subdirectory to make this more scalable.
- */
+// Copyright (C) 2002-2004 Andrew Tridgell
+// Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// Routines to handle the stats files. The stats file is stored one per cache
+// subdirectory to make this more scalable.
#include "ccache.h"
#include "hashutil.h"
static struct counters *counter_updates;
-#define FLAG_NOZERO 1 /* don't zero with the -z option */
-#define FLAG_ALWAYS 2 /* always show, even if zero */
-#define FLAG_NEVER 4 /* never show */
+#define FLAG_NOZERO 1 // don't zero with the -z option
+#define FLAG_ALWAYS 2 // always show, even if zero
+#define FLAG_NEVER 4 // never show
static void display_size_times_1024(uint64_t size);
-/* statistics fields in display order */
+// Statistics fields in display order.
static struct {
enum stats stat;
char *message;
{ STATS_DEVICE, "output to a non-regular file ", NULL, 0 },
{ STATS_NOINPUT, "no input file ", NULL, 0 },
{ STATS_BADEXTRAFILE, "error hashing extra file ", NULL, 0 },
+ { STATS_NUMCLEANUPS, "cleanups performed ", NULL, FLAG_ALWAYS },
{ STATS_NUMFILES, "files in cache ", NULL,
FLAG_NOZERO|FLAG_ALWAYS },
{ STATS_TOTALSIZE, "cache size ",
display_size(size * 1024);
}
-/* parse a stats file from a buffer - adding to the counters */
+// Parse a stats file from a buffer, adding to the counters.
static void
parse_stats(struct counters *counters, const char *buf)
{
size_t i = 0;
- const char *p;
- char *p2;
-
- p = buf;
+ const char *p = buf;
while (true) {
+ char *p2;
long val = strtol(p, &p2, 10);
if (p2 == p) {
break;
}
}
-/* write out a stats file */
+// Write out a stats file.
void
stats_write(const char *path, struct counters *counters)
{
- size_t i;
- char *tmp_file;
- FILE *f;
-
- tmp_file = format("%s.tmp", path);
- f = create_tmp_file(&tmp_file, "wb");
- for (i = 0; i < counters->size; i++) {
+ char *tmp_file = format("%s.tmp", path);
+ FILE *f = create_tmp_file(&tmp_file, "wb");
+ for (size_t i = 0; i < counters->size; i++) {
if (fprintf(f, "%u\n", counters->data[i]) < 0) {
fatal("Failed to write to %s", tmp_file);
}
}
}
-/*
- * Record that a number of bytes and files have been added to the cache. Size
- * is in bytes.
- */
+// Record that a number of bytes and files have been added to the cache. Size
+// is in bytes.
void
stats_update_size(uint64_t size, unsigned files)
{
counter_updates->data[STATS_TOTALSIZE] += size / 1024;
}
-/* Read in the stats from one directory and add to the counters. */
+// Read in the stats from one directory and add to the counters.
void
stats_read(const char *sfile, struct counters *counters)
{
free(data);
}
-/*
- * Write counter updates in counter_updates to disk.
- */
+// Write counter updates in counter_updates to disk.
void
stats_flush(void)
{
- struct counters *counters;
- bool need_cleanup = false;
- bool should_flush = false;
- int i;
-
assert(conf);
if (!conf->stats) {
return;
}
- for (i = 0; i < STATS_END; ++i) {
+ bool should_flush = false;
+ for (int i = 0; i < STATS_END; ++i) {
if (counter_updates->data[i] > 0) {
should_flush = true;
break;
if (!stats_file) {
char *stats_dir;
- /*
- * A NULL stats_file means that we didn't get past calculate_object_hash(),
- * so we just choose one of stats files in the 16 subdirectories.
- */
+ // A NULL stats_file means that we didn't get past calculate_object_hash(),
+ // so we just choose one of stats files in the 16 subdirectories.
stats_dir = format("%s/%x", conf->cache_dir, hash_from_int(getpid()) % 16);
stats_file = format("%s/stats", stats_dir);
free(stats_dir);
if (!lockfile_acquire(stats_file, lock_staleness_limit)) {
return;
}
- counters = counters_init(STATS_END);
+
+ struct counters *counters = counters_init(STATS_END);
stats_read(stats_file, counters);
- for (i = 0; i < STATS_END; ++i) {
+ for (int i = 0; i < STATS_END; ++i) {
counters->data[i] += counter_updates->data[i];
}
stats_write(stats_file, counters);
lockfile_release(stats_file);
if (!str_eq(conf->log_file, "")) {
- for (i = 0; i < STATS_END; ++i) {
+ for (int i = 0; i < STATS_END; ++i) {
if (counter_updates->data[stats_info[i].stat] != 0
&& !(stats_info[i].flags & FLAG_NOZERO)) {
cc_log("Result: %s", stats_info[i].message);
}
}
+ bool need_cleanup = false;
if (conf->max_files != 0
&& counters->data[STATS_NUMFILES] > conf->max_files / 16) {
need_cleanup = true;
counters_free(counters);
}
-/* update a normal stat */
+// Update a normal stat.
void
stats_update(enum stats stat)
{
counter_updates->data[stat]++;
}
-/* Get the pending update of a counter value. */
+// Get the pending update of a counter value.
unsigned
stats_get_pending(enum stats stat)
{
return counter_updates->data[stat];
}
-/* sum and display the total stats for all cache dirs */
+// Sum and display the total stats for all cache dirs.
void
stats_summary(struct conf *conf)
{
- int dir, i;
struct counters *counters = counters_init(STATS_END);
assert(conf);
- /* add up the stats in each directory */
- for (dir = -1; dir <= 0xF; dir++) {
+ // Add up the stats in each directory.
+ for (int dir = -1; dir <= 0xF; dir++) {
char *fname;
if (dir == -1) {
printf("secondary config (readonly) %s\n",
secondary_config_path ? secondary_config_path : "");
- /* and display them */
- for (i = 0; stats_info[i].message; i++) {
+ // ...and display them.
+ for (int i = 0; stats_info[i].message; i++) {
enum stats stat = stats_info[i].stat;
if (stats_info[i].flags & FLAG_NEVER) {
} else {
printf("%8u\n", counters->data[stat]);
}
+
+ if (stat == STATS_TOCACHE) {
+ unsigned direct = counters->data[STATS_CACHEHIT_DIR];
+ unsigned preprocessed = counters->data[STATS_CACHEHIT_CPP];
+ unsigned hit = direct + preprocessed;
+ unsigned miss = counters->data[STATS_TOCACHE];
+ unsigned total = hit + miss;
+ double percent = total > 0 ? (100.0f * hit) / total : 0.0f;
+ printf("cache hit rate %6.2f %%\n", percent);
+ }
}
if (conf->max_files != 0) {
counters_free(counters);
}
-/* zero all the stats structures */
+// Zero all the stats structures.
void
stats_zero(void)
{
- int dir;
- unsigned i;
- char *fname;
-
assert(conf);
- fname = format("%s/stats", conf->cache_dir);
+ char *fname = format("%s/stats", conf->cache_dir);
x_unlink(fname);
free(fname);
- for (dir = 0; dir <= 0xF; dir++) {
+ for (int dir = 0; dir <= 0xF; dir++) {
struct counters *counters = counters_init(STATS_END);
struct stat st;
fname = format("%s/%1x/stats", conf->cache_dir, dir);
if (stat(fname, &st) != 0) {
- /* No point in trying to reset the stats file if it doesn't exist. */
+ // No point in trying to reset the stats file if it doesn't exist.
free(fname);
continue;
}
if (lockfile_acquire(fname, lock_staleness_limit)) {
stats_read(fname, counters);
- for (i = 0; stats_info[i].message; i++) {
+ for (unsigned i = 0; stats_info[i].message; i++) {
if (!(stats_info[i].flags & FLAG_NOZERO)) {
counters->data[stats_info[i].stat] = 0;
}
}
}
-/* Get the per directory limits */
+// Get the per-directory limits.
void
stats_get_obsolete_limits(const char *dir, unsigned *maxfiles,
uint64_t *maxsize)
counters_free(counters);
}
-/* set the per directory sizes */
+// Set the per-directory sizes.
void
stats_set_sizes(const char *dir, unsigned num_files, uint64_t total_size)
{
struct counters *counters = counters_init(STATS_END);
- char *statsfile;
-
- statsfile = format("%s/stats", dir);
-
+ char *statsfile = format("%s/stats", dir);
if (lockfile_acquire(statsfile, lock_staleness_limit)) {
stats_read(statsfile, counters);
counters->data[STATS_NUMFILES] = num_files;
free(statsfile);
counters_free(counters);
}
+
+// Count directory cleanup run.
+void
+stats_add_cleanup(const char *dir, unsigned count)
+{
+ struct counters *counters = counters_init(STATS_END);
+ char *statsfile = format("%s/stats", dir);
+ if (lockfile_acquire(statsfile, lock_staleness_limit)) {
+ stats_read(statsfile, counters);
+ counters->data[STATS_NUMCLEANUPS] += count;
+ stats_write(statsfile, counters);
+ lockfile_release(statsfile);
+ }
+ free(statsfile);
+ counters_free(counters);
+}
-/*
- * 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
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef CCACHE_SYSTEM_H
#define CCACHE_SYSTEM_H
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
extern char **environ;
+#ifndef ESTALE
+#define ESTALE -1
+#endif
+
#if !HAVE_VSNPRINTF
int rpl_vsnprintf(char *, size_t, const char *, va_list);
#define vsnprintf rpl_vsnprintf
#define asprintf rpl_asprintf
#endif
-#ifdef HAVE_STDBOOL_H
-# include <stdbool.h>
-#else
-# ifndef HAVE__BOOL
-# ifdef __cplusplus
-typedef bool _Bool;
-# else
-# define _Bool signed char
-# endif
-# endif
-# define bool _Bool
-# define false 0
-# define true 1
-# define __bool_true_false_are_defined 1
-#endif
-
-#endif /* CCACHE_SYSTEM_H */
+#endif // CCACHE_SYSTEM_H
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-unset CCACHE_BASEDIR
-unset CCACHE_CC
-unset CCACHE_COMPILERCHECK
-unset CCACHE_COMPRESS
-unset CCACHE_CPP2
-unset CCACHE_DIR
-unset CCACHE_DISABLE
-unset CCACHE_EXTENSION
-unset CCACHE_EXTRAFILES
-unset CCACHE_HARDLINK
-unset CCACHE_HASHDIR
-unset CCACHE_LOGFILE
-unset CCACHE_NLEVELS
-unset CCACHE_NODIRECT
-unset CCACHE_NOSTATS
-unset CCACHE_PATH
-unset CCACHE_PREFIX
-unset CCACHE_READONLY
-unset CCACHE_READONLY_DIRECT
-unset CCACHE_RECACHE
-unset CCACHE_SLOPPINESS
-unset CCACHE_TEMPDIR
-unset CCACHE_UMASK
-unset CCACHE_UNIFY
-unset GCC_COLORS
-
-# Many tests backdate files, which updates their ctimes. In those tests, we
-# must ignore ctimes. Might as well do so everywhere.
-default_sloppiness=include_file_ctime
-CCACHE_SLOPPINESS="$default_sloppiness"
-export CCACHE_SLOPPINESS
+green() {
+ printf "\033[1;32m$*\033[0;0m\n"
+}
+
+red() {
+ printf "\033[1;31m$*\033[0;0m\n"
+}
+
+bold() {
+ printf "\033[1;37m$*\033[0;0m\n"
+}
test_failed() {
- echo "SUITE: \"$testsuite\", TEST: \"$testname\" - $1"
+ echo
+ red FAILED
+ echo
+ echo "Test suite: $(bold $CURRENT_SUITE)"
+ echo "Test case: $(bold $CURRENT_TEST)"
+ echo "Failure reason: $(red $1)"
+ echo
+ echo "ccache -s:"
$CCACHE -s
- cd ..
- echo TEST FAILED
+ echo
echo "Test data and log file have been left in $TESTDIR"
exit 1
}
-randcode() {
- outfile="$1"
- nlines=$2
- i=0
- (
- while [ $i -lt $nlines ]; do
- echo "int foo$nlines$i(int x) { return x; }"
- i=`expr $i + 1`
+generate_code() {
+ local nlines=$1
+ local outfile=$2
+
+ rm -f $outfile
+ for i in $(seq $nlines); do
+ echo "int foo_$i(int x) { return x; }" >>$outfile
done
- ) >> "$outfile"
}
-getstat() {
- stat="$1"
- value=`$CCACHE -s | grep "$stat" | cut -c34-`
- echo $value
+remove_cache() {
+ if [ -d $CCACHE_DIR ]; then
+ chmod -R +w $CCACHE_DIR
+ rm -rf $CCACHE_DIR
+ fi
+}
+
+clear_cache() {
+ $CCACHE -Cz >/dev/null
}
-checkstat() {
- stat="$1"
- expected_value="$2"
- value=`getstat "$stat"`
+sed_in_place() {
+ local expr=$1
+ shift
+
+ for file in $*; do
+ sed "$expr" $file >$file.sed
+ mv $file.sed $file
+ done
+}
+
+backdate() {
+ touch -t 199901010000 "$@"
+}
+
+expect_stat() {
+ local stat="$1"
+ local expected_value="$2"
+ local value="$(echo $($CCACHE -s | fgrep "$stat" | cut -c34-))"
+
if [ "$expected_value" != "$value" ]; then
- test_failed "Expected \"$stat\" to be $expected_value, got $value"
+ test_failed "Expected \"$stat\" to be $expected_value, actual $value"
fi
}
-compare_file() {
- cmp -s "$1" "$2"
+expect_equal_files() {
+ if [ ! -e "$1" ]; then
+ test_failed "compare_files: $1 missing"
+ fi
+ if [ ! -e "$2" ]; then
+ test_failed "compare_files: $2 missing"
+ fi
+ if ! cmp -s "$1" "$2"; then
+ test_failed "compare_files:: $1 and $2 differ"
+ fi
+}
+
+expect_equal_object_files() {
+ if $HOST_OS_LINUX && $COMPILER_TYPE_CLANG; then
+ if ! which eu-elfcmp >/dev/null 2>&1; then
+ test_failed "Please install elfutils to get eu-elfcmp"
+ fi
+ eu-elfcmp -q "$1" "$2"
+ else
+ cmp -s "$1" "$2"
+ fi
if [ $? -ne 0 ]; then
- test_failed "Files differ: $1 != $2"
+ test_failed "Objects differ: $1 != $2"
fi
}
-checkfile() {
- if [ ! -f $1 ]; then
- test_failed "$1 not found"
+expect_file_content() {
+ local file="$1"
+ local content="$2"
+
+ if [ ! -f "$file" ]; then
+ test_failed "$file not found"
fi
- if [ "`cat $1`" != "$2" ]; then
- test_failed "Bad content of $1.\nExpected: $2\nActual: `cat $1`"
+ if [ "$(cat $file)" != "$content" ]; then
+ test_failed "Bad content of $file.\nExpected: $content\nActual: $(cat $file)"
fi
}
-checkfilecount() {
- expected=$1
- pattern=$2
- dir=$3
- actual=`find $dir -name "$pattern" | wc -l`
+expect_file_count() {
+ local expected=$1
+ local pattern=$2
+ local dir=$3
+ local actual=`find $dir -name "$pattern" | wc -l`
if [ $actual -ne $expected ]; then
test_failed "Found $actual (expected $expected) $pattern files in $dir"
fi
}
-sed_in_place() {
- expr=$1
- shift
- for file in $*; do
- sed "$expr" > ${file}.sed < $file
- mv ${file}.sed $file
- done
+run_suite() {
+ local name=$1
+
+ CURRENT_SUITE=$name
+ UNCACHED_COMPILE=uncached_compile
+
+ cd $ABS_TESTDIR
+ rm -rf $ABS_TESTDIR/fixture
+
+ if type SUITE_${name}_PROBE >/dev/null 2>&1; then
+ mkdir $ABS_TESTDIR/probe
+ cd $ABS_TESTDIR/probe
+ local skip_reason="$(SUITE_${name}_PROBE)"
+ cd $ABS_TESTDIR
+ rm -rf $ABS_TESTDIR/probe
+ if [ -n "$skip_reason" ]; then
+ echo "Skipped test suite $name [$skip_reason]"
+ return
+ fi
+ fi
+
+ printf "Running test suite %s" "$(bold $name)"
+ SUITE_$name
+ echo
}
-backdate() {
- touch -t 199901010000 "$@"
+uncached_compile() {
+ # $COMPILER could be a masquerading system ccache, so make sure it's
+ # disabled:
+ CCACHE_DISABLE=1 $COMPILER "$@"
}
-run_suite() {
- rm -rf $CCACHE_DIR
- CCACHE_NODIRECT=1
- export CCACHE_NODIRECT
+TEST() {
+ CURRENT_TEST=$1
- echo "starting testsuite $1"
- testsuite=$1
+ unset CCACHE_BASEDIR
+ unset CCACHE_CC
+ unset CCACHE_COMMENTS
+ unset CCACHE_COMPILERCHECK
+ unset CCACHE_COMPRESS
+ unset CCACHE_CPP2
+ unset CCACHE_DIR
+ unset CCACHE_DISABLE
+ unset CCACHE_EXTENSION
+ unset CCACHE_EXTRAFILES
+ unset CCACHE_HARDLINK
+ unset CCACHE_IGNOREHEADERS
+ unset CCACHE_LIMIT_MULTIPLE
+ unset CCACHE_LOGFILE
+ unset CCACHE_NLEVELS
+ unset CCACHE_NOCPP2
+ unset CCACHE_NOHASHDIR
+ unset CCACHE_NOSTATS
+ unset CCACHE_PATH
+ unset CCACHE_PREFIX
+ unset CCACHE_PREFIX_CPP
+ unset CCACHE_READONLY
+ unset CCACHE_READONLY_DIRECT
+ unset CCACHE_RECACHE
+ unset CCACHE_SLOPPINESS
+ unset CCACHE_TEMPDIR
+ unset CCACHE_UMASK
+ unset CCACHE_UNIFY
+ unset GCC_COLORS
+
+ export CCACHE_CONFIGPATH=$ABS_TESTDIR/ccache.conf
+ export CCACHE_DETECT_SHEBANG=1
+ export CCACHE_DIR=$ABS_TESTDIR/.ccache
+ export CCACHE_LOGFILE=$ABS_TESTDIR/ccache.log
+ export CCACHE_NODIRECT=1
+
+ # Many tests backdate files, which updates their ctimes. In those tests, we
+ # must ignore ctimes. Might as well do so everywhere.
+ DEFAULT_SLOPPINESS=include_file_ctime
+ export CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS"
- ${1}_suite
+ CCACHE_COMPILE="$CCACHE $COMPILER"
- testname="the tmp directory should be empty"
- if [ -d $CCACHE_DIR/tmp ] && [ "`find $CCACHE_DIR/tmp -type f | wc -l`" -gt 0 ]; then
- test_failed "$CCACHE_DIR/tmp is not empty"
+ if $VERBOSE; then
+ printf "\n %s" $CURRENT_TEST
+ else
+ printf .
+ fi
+
+ cd /
+ remove_cache
+ rm -rf $ABS_TESTDIR/run
+ mkdir $ABS_TESTDIR/run
+ cd $ABS_TESTDIR/run
+ if type SUITE_${name}_SETUP >/dev/null 2>&1; then
+ SUITE_${name}_SETUP
fi
}
+# =============================================================================
+
base_tests() {
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
- checkstat 'files in cache' 0
-
- j=1
- rm -f *.c
- while [ $j -lt 32 ]; do
- randcode test$j.c $j
- j=`expr $j + 1`
- done
+ # -------------------------------------------------------------------------
+ TEST "Base case"
- CCACHE_DISABLE=1 $COMPILER -c -o reference_test1.o test1.c
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
- testname="BASIC"
$CCACHE_COMPILE -c test1.c
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkstat 'files in cache' 1
- compare_file reference_test1.o test1.o
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
- testname="BASIC2"
$CCACHE_COMPILE -c test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
- checkstat 'files in cache' 1
- compare_file reference_test1.o test1.o
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
+
+ # -------------------------------------------------------------------------
+ TEST "Debug option"
- testname="debug"
$CCACHE_COMPILE -c test1.c -g
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 2
- checkstat 'files in cache' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
- testname="debug2"
$CCACHE_COMPILE -c test1.c -g
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 2
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c -g
+ expect_equal_object_files reference_test1.o reference_test1.o
+
+ # -------------------------------------------------------------------------
+ TEST "Output option"
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- testname="output"
$CCACHE_COMPILE -c test1.c -o foo.o
- checkstat 'cache hit (preprocessed)' 3
- checkstat 'cache miss' 2
- compare_file reference_test1.o foo.o
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+ expect_equal_object_files reference_test1.o foo.o
+
+ # -------------------------------------------------------------------------
+ TEST "Called for link"
+
+ $CCACHE_COMPILE test1.c -o test 2>/dev/null
+ expect_stat 'called for link' 1
- testname="link"
- $CCACHE_COMPILE test1.c -o test 2> /dev/null
- checkstat 'called for link' 1
+ $CCACHE_COMPILE -c test1.c
+ $CCACHE_COMPILE test1.o -o test 2>/dev/null
+ expect_stat 'called for link' 2
+
+ # -------------------------------------------------------------------------
+ TEST "No input file"
+
+ $CCACHE_COMPILE -c foo.c 2>/dev/null
+ expect_stat 'no input file' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Called for preprocessing"
- testname="linkobj"
- $CCACHE_COMPILE foo.o -o test 2> /dev/null
- checkstat 'called for link' 2
+ $CCACHE_COMPILE -E -c test1.c >/dev/null 2>&1
+ expect_stat 'called for preprocessing' 1
- testname="preprocessing"
- $CCACHE_COMPILE -E -c test1.c > /dev/null 2>&1
- checkstat 'called for preprocessing' 1
+ # -------------------------------------------------------------------------
+ TEST "Multiple source files"
- testname="multiple"
+ touch test2.c
$CCACHE_COMPILE -c test1.c test2.c
- checkstat 'multiple source files' 1
+ expect_stat 'multiple source files' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Couldn't find the compiler"
+
+ $CCACHE blahblah -c test1.c 2>/dev/null
+ expect_stat "couldn't find the compiler" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Bad compiler arguments"
- testname="find"
- $CCACHE blahblah -c test1.c 2> /dev/null
- checkstat "couldn't find the compiler" 1
+ $CCACHE_COMPILE -c test1.c -I 2>/dev/null
+ expect_stat 'bad compiler arguments' 1
- testname="bad"
- $CCACHE_COMPILE -c test1.c -I 2> /dev/null
- checkstat 'bad compiler arguments' 1
+ # -------------------------------------------------------------------------
+ TEST "Unsupported source language"
- testname="unsupported source language"
ln -f test1.c test1.ccc
- $CCACHE_COMPILE -c test1.ccc 2> /dev/null
- checkstat 'unsupported source language' 1
+ $CCACHE_COMPILE -c test1.ccc 2>/dev/null
+ expect_stat 'unsupported source language' 1
- testname="unsupported"
- $CCACHE_COMPILE -M foo -c test1.c > /dev/null 2>&1
- checkstat 'unsupported compiler option' 1
+ # -------------------------------------------------------------------------
+ TEST "Unsupported compiler option"
- testname="stdout"
- $CCACHE echo foo -c test1.c > /dev/null
- checkstat 'compiler produced stdout' 1
+ $CCACHE_COMPILE -M foo -c test1.c >/dev/null 2>&1
+ expect_stat 'unsupported compiler option' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Compiler produced stdout"
+
+ $CCACHE echo foo -c test1.c >/dev/null
+ expect_stat 'compiler produced stdout' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Output to a non-regular file"
- testname="non-regular"
mkdir testd
- $CCACHE_COMPILE -o testd -c test1.c > /dev/null 2>&1
- rmdir testd > /dev/null 2>&1
- checkstat 'output to a non-regular file' 1
-
- testname="no-input"
- $CCACHE_COMPILE -c -O2 2> /dev/null
- checkstat 'no input file' 1
-
- testname="CCACHE_DISABLE"
- mv $CCACHE_DIR $CCACHE_DIR.saved
- saved_config_path=$CCACHE_CONFIGPATH
- unset CCACHE_CONFIGPATH
- CCACHE_DISABLE=1 $CCACHE_COMPILE -c test1.c 2> /dev/null
+ $CCACHE_COMPILE -o testd -c test1.c >/dev/null 2>&1
+ rmdir testd >/dev/null 2>&1
+ expect_stat 'output to a non-regular file' 1
+
+ # -------------------------------------------------------------------------
+ TEST "No input file"
+
+ $CCACHE_COMPILE -c -O2 2>/dev/null
+ expect_stat 'no input file' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_DISABLE"
+
+ CCACHE_DISABLE=1 $CCACHE_COMPILE -c test1.c 2>/dev/null
if [ -d $CCACHE_DIR ]; then
test_failed "$CCACHE_DIR created despite CCACHE_DISABLE being set"
fi
- CCACHE_CONFIGPATH=$saved_config_path
- mv $CCACHE_DIR.saved $CCACHE_DIR
- checkstat 'cache hit (preprocessed)' 3
- $CCACHE_COMPILE -c test1.c
- checkstat 'cache hit (preprocessed)' 4
- testname="CCACHE_CPP2"
- CCACHE_CPP2=1 $CCACHE_COMPILE -c test1.c -O -O
- checkstat 'cache hit (preprocessed)' 4
- checkstat 'cache miss' 3
- CCACHE_DISABLE=1 $COMPILER -c test1.c -o reference_test1.o -O -O
- compare_file reference_test1.o test1.o
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMMENTS"
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+
+ mv test1.c test1-saved.c
+ echo '// initial comment' >test1.c
+ cat test1-saved.c >>test1.c
+ CCACHE_COMMENTS=1 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ echo '// different comment' >test1.c
+ cat test1-saved.c >>test1.c
+ CCACHE_COMMENTS=1 $CCACHE_COMPILE -c test1.c
+ mv test1-saved.c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+ expect_equal_object_files reference_test1.o test1.o
- CCACHE_CPP2=1 $CCACHE_COMPILE -c test1.c -O -O
- checkstat 'cache hit (preprocessed)' 5
- checkstat 'cache miss' 3
- compare_file reference_test1.o test1.o
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_NOSTATS"
- testname="CCACHE_NOSTATS"
CCACHE_NOSTATS=1 $CCACHE_COMPILE -c test1.c -O -O
- checkstat 'cache hit (preprocessed)' 5
- checkstat 'cache miss' 3
-
- testname="CCACHE_RECACHE"
- CCACHE_RECACHE=1 $CCACHE_COMPILE -c test1.c -O -O
- checkstat 'cache hit (preprocessed)' 5
- checkstat 'cache miss' 4
- compare_file reference_test1.o test1.o
-
- # strictly speaking should be 4 - RECACHE causes a double counting!
- checkstat 'files in cache' 4
- $CCACHE -c > /dev/null
- checkstat 'files in cache' 4
-
- testname="CCACHE_HASHDIR"
- CCACHE_HASHDIR=1 $CCACHE_COMPILE -c test1.c -O -O
- checkstat 'cache hit (preprocessed)' 5
- checkstat 'cache miss' 5
- compare_file reference_test1.o test1.o
-
- CCACHE_HASHDIR=1 $CCACHE_COMPILE -c test1.c -O -O
- checkstat 'cache hit (preprocessed)' 6
- checkstat 'cache miss' 5
- checkstat 'files in cache' 5
- compare_file reference_test1.o test1.o
-
- testname="comments"
- echo '/* a silly comment */' > test1-comment.c
- cat test1.c >> test1-comment.c
- $CCACHE_COMPILE -c test1-comment.c
- rm -f test1-comment*
- checkstat 'cache hit (preprocessed)' 6
- checkstat 'cache miss' 6
-
- testname="CCACHE_UNIFY"
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_RECACHE"
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_RECACHE=1 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+ expect_equal_object_files reference_test1.o test1.o
+
+ # CCACHE_RECACHE replaces the object file, so the statistics counter will
+ # be off-by-one until next cleanup.
+ expect_stat 'files in cache' 2
+ $CCACHE -c >/dev/null
+ expect_stat 'files in cache' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Directory is hashed if using -g"
+
+ mkdir dir1 dir2
+ cp test1.c dir1
+ cp test1.c dir2
+
+ cd dir1
+ $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ cd ../dir2
+ $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+ $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Directory is not hashed if not using -g"
+
+ mkdir dir1 dir2
+ cp test1.c dir1
+ cp test1.c dir2
+
+ cd dir1
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ cd ../dir2
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_NOHASHDIR"
+
+ mkdir dir1 dir2
+ cp test1.c dir1
+ cp test1.c dir2
+
+ cd dir1
+ CCACHE_NOHASHDIR=1 $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ CCACHE_NOHASHDIR=1 $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ cd ../dir2
+ CCACHE_NOHASHDIR=1 $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_UNIFY"
+
+ echo '// a silly comment' >>test1.c
CCACHE_UNIFY=1 $CCACHE_COMPILE -c test1.c
- checkstat 'cache hit (preprocessed)' 6
- checkstat 'cache miss' 7
- mv test1.c test1-saved.c
- echo '/* another comment */' > test1.c
- cat test1-saved.c >> test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo '// another silly comment' >>test1.c
CCACHE_UNIFY=1 $CCACHE_COMPILE -c test1.c
- mv test1-saved.c test1.c
- checkstat 'cache hit (preprocessed)' 7
- checkstat 'cache miss' 7
- CCACHE_DISABLE=1 $COMPILER -c test1.c -o reference_test1.o
- compare_file reference_test1.o test1.o
-
- testname="cache-size"
- for f in *.c; do
- $CCACHE_COMPILE -c $f
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+ expect_equal_object_files reference_test1.o test1.o
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_NLEVELS"
+
+ CCACHE_NLEVELS=4 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+
+ CCACHE_NLEVELS=4 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+
+ # Directories in $CCACHE_DIR:
+ # - .
+ # - tmp
+ # - a
+ # - a/b
+ # - a/b/c
+ # - a/b/c/d
+ actual_dirs=$(find $CCACHE_DIR -type d | wc -l)
+ expected_dirs=6
+ if [ $actual_dirs -ne $expected_dirs ]; then
+ test_failed "Expected $expected_dirs directories, found $actual_dirs"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_EXTRAFILES"
+
+ echo a >a
+ echo b >b
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
+
+ echo b2 >b
+
+ CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 3
+
+ CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 3
+ expect_stat 'cache miss' 3
+
+ CCACHE_EXTRAFILES="doesntexist" $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 3
+ expect_stat 'cache miss' 3
+ expect_stat 'error hashing extra file' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_PREFIX"
+
+ cat <<'EOF' >prefix-a
+#!/bin/sh
+echo a >>prefix.result
+exec "$@"
+EOF
+ cat <<'EOF' >prefix-b
+#!/bin/sh
+echo b >>prefix.result
+exec "$@"
+EOF
+ chmod +x prefix-a prefix-b
+ cat <<'EOF' >file.c
+int foo;
+EOF
+ PATH=.:$PATH CCACHE_PREFIX="prefix-a prefix-b" $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_file_content prefix.result "a
+b"
+
+ PATH=.:$PATH CCACHE_PREFIX="prefix-a prefix-b" $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_file_content prefix.result "a
+b"
+
+ rm -f prefix.result
+ PATH=.:$PATH CCACHE_PREFIX_CPP="prefix-a prefix-b" $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+ expect_file_content prefix.result "a
+b"
+
+ # -------------------------------------------------------------------------
+ TEST "Files in cache"
+
+ for i in $(seq 32); do
+ generate_code $i test$i.c
+ $CCACHE_COMPILE -c test$i.c
done
- checkstat 'cache hit (preprocessed)' 8
- checkstat 'cache miss' 37
- checkstat 'files in cache' 37
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 32
+ expect_stat 'files in cache' 32
- $CCACHE -C >/dev/null
+ # -------------------------------------------------------------------------
+ TEST "Called for preprocessing"
- testname="cpp call"
- $CCACHE_COMPILE -c test1.c -E > test1.i
- checkstat 'cache hit (preprocessed)' 8
- checkstat 'cache miss' 37
+ $CCACHE_COMPILE -c test1.c -E >test1.i
+ expect_stat 'called for preprocessing' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Direct .i compile"
- testname="direct .i compile"
$CCACHE_COMPILE -c test1.c
- checkstat 'cache hit (preprocessed)' 8
- checkstat 'cache miss' 38
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ $UNCACHED_COMPILE -c test1.c -E >test1.i
$CCACHE_COMPILE -c test1.i
- checkstat 'cache hit (preprocessed)' 9
- checkstat 'cache miss' 38
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
- $CCACHE_COMPILE -c test1.i
- checkstat 'cache hit (preprocessed)' 10
- checkstat 'cache miss' 38
+ # -------------------------------------------------------------------------
+ TEST "-x c"
+
+ ln -f test1.c test1.ccc
- testname="-x c"
$CCACHE_COMPILE -x c -c test1.ccc
- checkstat 'cache hit (preprocessed)' 10
- checkstat 'cache miss' 39
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
$CCACHE_COMPILE -x c -c test1.ccc
- checkstat 'cache hit (preprocessed)' 11
- checkstat 'cache miss' 39
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-xc"
+
+ ln -f test1.c test1.ccc
+
+ $CCACHE_COMPILE -xc -c test1.ccc
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- testname="-xc"
$CCACHE_COMPILE -xc -c test1.ccc
- checkstat 'cache hit (preprocessed)' 12
- checkstat 'cache miss' 39
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-x none"
+
+ $CCACHE_COMPILE -x assembler -x none -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- testname="-x none"
$CCACHE_COMPILE -x assembler -x none -c test1.c
- checkstat 'cache hit (preprocessed)' 13
- checkstat 'cache miss' 39
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-x unknown"
- testname="-x unknown"
$CCACHE_COMPILE -x unknown -c test1.c 2>/dev/null
- checkstat 'cache hit (preprocessed)' 13
- checkstat 'cache miss' 39
- checkstat 'unsupported source language' 2
-
- testname="-D not hashed"
- $CCACHE_COMPILE -DNOT_AFFECTING=1 -c test1.c 2>/dev/null
- checkstat 'cache hit (preprocessed)' 14
- checkstat 'cache miss' 39
-
- if [ -x /usr/bin/printf ]; then
- /usr/bin/printf '#include <wchar.h>\nwchar_t foo[] = L"\xbf";\n' >latin1.c
- if CCACHE_DISABLE=1 $COMPILER -c -finput-charset=latin1 latin1.c >/dev/null 2>&1; then
- testname="-finput-charset"
- CCACHE_CPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
- checkstat 'cache hit (preprocessed)' 14
- checkstat 'cache miss' 40
- 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
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'unsupported source language' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-D not hashed"
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -DNOT_AFFECTING=1 -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-S"
+
+ $CCACHE_COMPILE -S test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -S test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c test1.s
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ $CCACHE_COMPILE -c test1.s
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_PATH"
- testname="override path"
- $CCACHE -Cz >/dev/null
override_path=`pwd`/override_path
- rm -rf $override_path
mkdir $override_path
cat >$override_path/cc <<EOF
#!/bin/sh
test_failed "CCACHE_PATH had no effect"
fi
- testname="compilercheck=mtime"
- $CCACHE -Cz >/dev/null
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=mtime"
+
cat >compiler.sh <<EOF
#!/bin/sh
-CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
-export CCACHE_DISABLE
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
exec $COMPILER "\$@"
# A comment
EOF
chmod +x compiler.sh
backdate compiler.sh
CCACHE_COMPILERCHECK=mtime $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
sed_in_place 's/comment/yoghurt/' compiler.sh # Don't change the size
chmod +x compiler.sh
- backdate compiler.sh
+ backdate compiler.sh # Don't change the timestamp
+
CCACHE_COMPILERCHECK=mtime $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
touch compiler.sh
CCACHE_COMPILERCHECK=mtime $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 2
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=content"
+
+ cat >compiler.sh <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+exec $COMPILER "\$@"
+EOF
+ chmod +x compiler.sh
- testname="compilercheck=content"
- $CCACHE -z >/dev/null
CCACHE_COMPILERCHECK=content $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- backdate compiler.sh
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
CCACHE_COMPILERCHECK=content $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
echo "# Compiler upgrade" >>compiler.sh
- backdate compiler.sh
+
CCACHE_COMPILERCHECK=content $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 2
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=none"
+
+ cat >compiler.sh <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+exec $COMPILER "\$@"
+EOF
+ chmod +x compiler.sh
- testname="compilercheck=none"
- $CCACHE -z >/dev/null
- backdate compiler.sh
CCACHE_COMPILERCHECK=none $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
CCACHE_COMPILERCHECK=none $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
echo "# Compiler upgrade" >>compiler.sh
CCACHE_COMPILERCHECK=none $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 1
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=string"
+
+ cat >compiler.sh <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+exec $COMPILER "\$@"
+EOF
+ chmod +x compiler.sh
- 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
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
CCACHE_COMPILERCHECK=string:foo $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
CCACHE_COMPILERCHECK=string:bar $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 2
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
CCACHE_COMPILERCHECK=string:bar $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 2
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=command"
+
+ cat >compiler.sh <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+exec $COMPILER "\$@"
+EOF
+ chmod +x compiler.sh
- testname="compilercheck=command"
- $CCACHE -z >/dev/null
- backdate compiler.sh
CCACHE_COMPILERCHECK='echo %compiler%' $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
echo "# Compiler upgrade" >>compiler.sh
CCACHE_COMPILERCHECK="echo ./compiler.sh" $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
cat <<EOF >foobar.sh
#!/bin/sh
echo foo
EOF
chmod +x foobar.sh
CCACHE_COMPILERCHECK='./foobar.sh' $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 2
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
CCACHE_COMPILERCHECK='echo foo; echo bar' $CCACHE ./compiler.sh -c test1.c
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 2
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=unknown_command"
+
+ cat >compiler.sh <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+exec $COMPILER "\$@"
+EOF
+ chmod +x compiler.sh
- testname="compilercheck=unknown_command"
- $CCACHE -z >/dev/null
- backdate compiler.sh
CCACHE_COMPILERCHECK="unknown_command" $CCACHE ./compiler.sh -c test1.c 2>/dev/null
if [ "$?" -eq 0 ]; then
test_failed "Expected failure running unknown_command to verify compiler but was success"
fi
- checkstat 'compiler check failed' 1
+ expect_stat 'compiler check failed' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_RECACHE should remove previous .stderr"
- testname="recache should remove previous .stderr"
- $CCACHE -Cz >/dev/null
$CCACHE_COMPILE -c test1.c
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
num=`find $CCACHE_DIR -name '*.stderr' | wc -l`
if [ $num -ne 0 ]; then
test_failed "$num stderr files found, expected 0 (#1)"
fi
+
obj_file=`find $CCACHE_DIR -name '*.o'`
stderr_file=`echo $obj_file | sed 's/..$/.stderr/'`
echo "Warning: foo" >$stderr_file
test_failed "$num stderr files found, expected 0 (#2)"
fi
- testname="no object file"
- $CCACHE -Cz >/dev/null
+ # -------------------------------------------------------------------------
+ TEST "No object file"
+
cat <<'EOF' >test_no_obj.c
int test_no_obj;
EOF
cat <<'EOF' >prefix-remove.sh
#!/bin/sh
"$@"
+[ x$2 = x-fcolor-diagnostics ] && shift
+[ x$2 = x-fdiagnostics-color ] && shift
+[ x$2 = x-std=gnu99 ] && shift
[ x$3 = x-o ] && rm $4
EOF
chmod +x prefix-remove.sh
CCACHE_PREFIX=`pwd`/prefix-remove.sh $CCACHE_COMPILE -c test_no_obj.c
- checkstat 'compiler produced no output' 1
+ expect_stat 'compiler produced no output' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Empty object file"
- testname="empty object file"
cat <<'EOF' >test_empty_obj.c
int test_empty_obj;
EOF
cat <<'EOF' >prefix-empty.sh
#!/bin/sh
"$@"
+[ x$2 = x-fcolor-diagnostics ] && shift
+[ x$2 = x-fdiagnostics-color ] && shift
+[ x$2 = x-std=gnu99 ] && shift
[ x$3 = x-o ] && cp /dev/null $4
EOF
chmod +x prefix-empty.sh
CCACHE_PREFIX=`pwd`/prefix-empty.sh $CCACHE_COMPILE -c test_empty_obj.c
- checkstat 'compiler produced empty output' 1
+ expect_stat 'compiler produced empty output' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Caching stderr"
- testname="stderr-files"
- $CCACHE -Cz >/dev/null
- num=`find $CCACHE_DIR -name '*.stderr' | wc -l`
- if [ $num -ne 0 ]; then
- test_failed "$num stderr files found, expected 0"
- fi
cat <<EOF >stderr.c
int stderr(void)
{
- /* Trigger warning by having no return statement. */
+ // Trigger warning by having no return statement.
}
EOF
- checkstat 'files in cache' 0
$CCACHE_COMPILE -Wall -W -c stderr.c 2>/dev/null
num=`find $CCACHE_DIR -name '*.stderr' | wc -l`
if [ $num -ne 1 ]; then
test_failed "$num stderr files found, expected 1"
fi
- checkstat 'files in cache' 2
-
- testname="zero-stats"
- $CCACHE -z > /dev/null
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
- checkstat 'files in cache' 2
-
- testname="clear"
- $CCACHE -C > /dev/null
- checkstat 'files in cache' 0
-
- # the profile options do not seem to work correctly with clang or gcc-llvm
- # on darwin machines
- darwin_llvm=0
- if [ $HOST_OS_APPLE -eq 1 ] && [ $COMPILER_USES_LLVM -eq 1 ]; then
- darwin_llvm=1
- fi
+ expect_stat 'files in cache' 2
- $COMPILER -c -fprofile-generate test1.c 2>/dev/null
- if [ $? -eq 0 ] && [ $darwin_llvm -eq 0 ]; then
- testname="profile-generate"
- $CCACHE -Cz > /dev/null
- $CCACHE_COMPILE -c -fprofile-generate test1.c
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkstat 'files in cache' 1
- $CCACHE_COMPILE -c -fprofile-generate test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
- checkstat 'files in cache' 1
-
- testname="profile-arcs"
- $CCACHE_COMPILE -c -fprofile-arcs test1.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 2
- checkstat 'files in cache' 2
- $CCACHE_COMPILE -c -fprofile-arcs test1.c
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 2
- checkstat 'files in cache' 2
-
- testname="profile-use"
- $CCACHE_COMPILE -c -fprofile-use test1.c 2>/dev/null
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 3
- $CCACHE_COMPILE -c -fprofile-use test1.c 2>/dev/null
- checkstat 'cache hit (preprocessed)' 3
- checkstat 'cache miss' 3
- fi
+ # -------------------------------------------------------------------------
+ TEST "--zero-stats"
+
+ $CCACHE_COMPILE -c test1.c
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+
+ $CCACHE -z >/dev/null
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'files in cache' 1
+
+ # -------------------------------------------------------------------------
+ TEST "--clear"
+
+ $CCACHE_COMPILE -c test1.c
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+
+ $CCACHE -C >/dev/null
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 0
+
+ # -------------------------------------------------------------------------
+ TEST "-P"
+
+ # Check that -P disables ccache. (-P removes preprocessor information in
+ # such a way that the object file from compiling the preprocessed file will
+ # not be equal to the object file produced when compiling without ccache.)
+
+ $CCACHE_COMPILE -c -P test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'unsupported compiler option' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-Wp,-P"
- ##################################################################
# Check that -Wp,-P disables ccache. (-P removes preprocessor information
# in such a way that the object file from compiling the preprocessed file
# will not be equal to the object file produced when compiling without
# ccache.)
- testname="-Wp,-P"
- $CCACHE -Cz >/dev/null
- $CCACHE_COMPILE -c -Wp,-P test1.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
- checkstat 'unsupported compiler option' 1
+
$CCACHE_COMPILE -c -Wp,-P test1.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
- checkstat 'unsupported compiler option' 2
- $CCACHE_COMPILE -c -Wp,-DFOO,-P,-DGOO test1.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
- checkstat 'unsupported compiler option' 3
- $CCACHE_COMPILE -c -Wp,-DFOO,-P,-DGOO test1.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
- checkstat 'unsupported compiler option' 4
-
- ##################################################################
-
- if [ $COMPILER_TYPE_CLANG -eq 1 ]; then
- testname="serialize-diagnostics"
- $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
- 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
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'unsupported compiler option' 1
+
+ $CCACHE_COMPILE -c -Wp,-P,-DFOO test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'unsupported compiler option' 2
+
+ $CCACHE_COMPILE -c -Wp,-DFOO,-P test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'unsupported compiler option' 3
+
+ # -------------------------------------------------------------------------
+ TEST "-Wp,-D"
+
+ $CCACHE_COMPILE -c -Wp,-DFOO test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c -DFOO test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Buggy GCC 6 cpp"
+
+ cat >buggy-cpp <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+if echo "\$*" | grep -- -D >/dev/null; then
+ $COMPILER "\$@"
+else
+ # Mistreat the preprocessor output in the same way as GCC 6 does.
+ $COMPILER "\$@" |
+ sed -e '/^# 1 "<command-line>"\$/ a\\
+# 31 "<command-line>"' \\
+ -e 's/^# 1 "<command-line>" 2\$/# 32 "<command-line>" 2/'
+fi
+exit 0
+EOF
+ cat <<'EOF' >file.c
+int foo;
+EOF
+ chmod +x buggy-cpp
+
+ $CCACHE ./buggy-cpp -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE ./buggy-cpp -DNOT_AFFECTING=1 -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Symlink to source directory"
+
+ mkdir dir
+ cd dir
+ mkdir -p d1/d2
+ echo '#define A "OK"' >d1/h.h
+ cat <<EOF >d1/d2/c.c
+#include <stdio.h>
+#include "../h.h"
+int main() { printf("%s\n", A); }
+EOF
+ echo '#define A "BUG"' >h.h
+ ln -s d1/d2 d3
+
+ CCACHE_BASEDIR=/ $CCACHE_COMPILE -c $PWD/d3/c.c
+ $UNCACHED_COMPILE c.o -o c
+ if [ "$(./c)" != OK ]; then
+ test_failed "Incorrect header file used"
fi
- ##################################################################
+ # -------------------------------------------------------------------------
+ TEST "Symlink to source file"
- rm -f test1.c
+ mkdir dir
+ cd dir
+ mkdir d
+ echo '#define A "BUG"' >d/h.h
+ cat <<EOF >d/c.c
+#include <stdio.h>
+#include "h.h"
+int main() { printf("%s\n", A); }
+EOF
+ echo '#define A "OK"' >h.h
+ ln -s d/c.c c.c
+
+ CCACHE_BASEDIR=/ $CCACHE_COMPILE -c $PWD/c.c
+ $UNCACHED_COMPILE c.o -o c
+ if [ "$(./c)" != OK ]; then
+ test_failed "Incorrect header file used"
+ fi
}
-base_suite() {
- CCACHE_COMPILE="$CCACHE $COMPILER"
+# =============================================================================
+
+SUITE_base_SETUP() {
+ generate_code 1 test1.c
+}
+
+SUITE_base() {
base_tests
}
-link_suite() {
- if [ `dirname $COMPILER` = . ]; then
- ln -s "$CCACHE" $COMPILER
- CCACHE_COMPILE="./$COMPILER"
- base_tests
- rm -f $COMPILER
- else
- echo "Compiler ($COMPILER) not taken from PATH -- not running link test"
- fi
+# =============================================================================
+
+SUITE_nocpp2_SETUP() {
+ export CCACHE_NOCPP2=1
+ generate_code 1 test1.c
}
-hardlink_suite() {
- CCACHE_COMPILE="$CCACHE $COMPILER"
- CCACHE_HARDLINK=1
- export CCACHE_HARDLINK
+SUITE_nocpp2() {
base_tests
- unset CCACHE_HARDLINK
}
-cpp2_suite() {
- CCACHE_COMPILE="$CCACHE $COMPILER"
- CCACHE_CPP2=1
- export CCACHE_CPP2
- base_tests
- unset CCACHE_CPP2
+# =============================================================================
+
+SUITE_multi_arch_PROBE() {
+ if ! $HOST_OS_APPLE; then
+ echo "multiple -arch options not supported on $(uname -s)"
+ return
+ fi
}
-nlevels4_suite() {
- CCACHE_COMPILE="$CCACHE $COMPILER"
- CCACHE_NLEVELS=4
- export CCACHE_NLEVELS
- base_tests
- unset CCACHE_NLEVELS
+SUITE_multi_arch() {
+ # -------------------------------------------------------------------------
+ TEST "cache hit"
+
+ generate_code 1 test1.c
+
+ $CCACHE_COMPILE -arch i386 -arch x86_64 -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -arch i386 -arch x86_64 -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+}
+
+# =============================================================================
+
+SUITE_serialize_diagnostics_PROBE() {
+ touch test.c
+ if ! $UNCACHED_COMPILE -c --serialize-diagnostics \
+ test1.dia test.c 2>/dev/null; then
+ echo "--serialize-diagnostics not supported by compiler"
+ fi
+}
+
+SUITE_serialize_diagnostics_SETUP() {
+ generate_code 1 test1.c
+}
+
+SUITE_serialize_diagnostics() {
+ # -------------------------------------------------------------------------
+ TEST "Compile OK"
+
+ $UNCACHED_COMPILE -c --serialize-diagnostics expected.dia test1.c
+
+ $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2
+ expect_equal_files expected.dia test.dia
+
+ rm test.dia
+
+ $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2
+ expect_equal_files expected.dia test.dia
+
+ # -------------------------------------------------------------------------
+ TEST "Compile failed"
+
+ echo "bad source" >error.c
+ if $UNCACHED_COMPILE -c --serialize-diagnostics expected.dia error.c 2>expected.stderr; then
+ test_failed "Expected an error compiling error.c"
+ fi
+
+ $CCACHE_COMPILE -c --serialize-diagnostics test.dia error.c 2>test.stderr
+ expect_stat 'compile failed' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'files in cache' 0
+ expect_equal_files expected.dia test.dia
+ expect_equal_files expected.stderr test.stderr
+
+ # -------------------------------------------------------------------------
+ TEST "--serialize-diagnostics + CCACHE_BASEDIR"
+
+ mkdir -p dir1/src dir1/include
+ cat <<EOF >dir1/src/test.c
+#include <stdarg.h>
+#include <test.h>
+EOF
+ cat <<EOF >dir1/include/test.h
+int test;
+EOF
+ cp -r dir1 dir2
+ backdate dir1/include/test.h dir2/include/test.h
+
+ cat <<EOF >stderr.h
+int stderr(void)
+{
+ // Trigger warning by having no return statement.
+}
+EOF
+
+ unset CCACHE_NODIRECT
+
+ cd dir1
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -w -MD -MF `pwd`/test.d -I`pwd`/include --serialize-diagnostics `pwd`/test.dia -c src/test.c -o `pwd`/test.o
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 4
+
+ cd ../dir2
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -w -MD -MF `pwd`/test.d -I`pwd`/include --serialize-diagnostics `pwd`/test.dia -c src/test.c -o `pwd`/test.o
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 4
+}
+
+# =============================================================================
+
+SUITE_debug_prefix_map_PROBE() {
+ if ! $COMPILER_TYPE_GCC || $COMPILER_USES_MINGW; then
+ echo "-fdebug-prefix-map not supported by compiler"
+ fi
+}
+
+SUITE_debug_prefix_map_SETUP() {
+ unset CCACHE_NODIRECT
+
+ mkdir -p dir1/src dir1/include
+ cat <<EOF >dir1/src/test.c
+#include <stdarg.h>
+#include <test.h>
+EOF
+ cat <<EOF >dir1/include/test.h
+int test;
+EOF
+ cp -r dir1 dir2
+ backdate dir1/include/test.h dir2/include/test.h
+}
+
+SUITE_debug_prefix_map() {
+ # -------------------------------------------------------------------------
+ TEST "Mapping of debug info CWD"
+
+ cd dir1
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -I`pwd`/include -g -fdebug-prefix-map=`pwd`=dir -c `pwd`/src/test.c -o `pwd`/test.o
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2
+ if grep -E "[^=]`pwd`[^=]" test.o >/dev/null 2>&1; then
+ test_failed "Source dir (`pwd`) found in test.o"
+ fi
+
+ cd ../dir2
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -I`pwd`/include -g -fdebug-prefix-map=`pwd`=dir -c `pwd`/src/test.c -o `pwd`/test.o
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2
+ if grep -E "[^=]`pwd`[^=]" test.o >/dev/null 2>&1; then
+ test_failed "Source dir (`pwd`) found in test.o"
+ fi
+}
+
+# =============================================================================
+
+SUITE_masquerading_PROBE() {
+ local compiler_binary=$(echo $COMPILER | cut -d' ' -f1)
+ if [ "$(dirname $compiler_binary)" != . ]; then
+ echo "compiler ($compiler_binary) not taken from PATH"
+ fi
+}
+
+SUITE_masquerading_SETUP() {
+ local compiler_binary=$(echo $COMPILER | cut -d' ' -f1)
+ local compiler_args=$(echo $COMPILER | cut -s -d' ' -f2-)
+
+ ln -s "$CCACHE" $compiler_binary
+ CCACHE_COMPILE="./$compiler_binary $compiler_args"
+ generate_code 1 test1.c
+}
+
+SUITE_masquerading() {
+ # -------------------------------------------------------------------------
+ TEST "Masquerading via symlink"
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
+}
+
+# =============================================================================
+
+SUITE_hardlink_PROBE() {
+ touch file1
+ if ! ln file1 file2 >/dev/null 2>&1; then
+ echo "file system doesn't support hardlinks"
+ fi
}
-nlevels1_suite() {
- CCACHE_COMPILE="$CCACHE $COMPILER"
- CCACHE_NLEVELS=1
- export CCACHE_NLEVELS
- base_tests
- unset CCACHE_NLEVELS
+SUITE_hardlink() {
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_HARDLINK"
+
+ generate_code 1 test1.c
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
+
+ CCACHE_HARDLINK=1 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
+
+ local obj_in_cache=$(find $CCACHE_DIR -name '*.o')
+ if [ ! $obj_in_cache -ef test1.o ]; then
+ test_failed "Object file not hard-linked to cached object file"
+ fi
}
-direct_suite() {
+# =============================================================================
+
+SUITE_direct_SETUP() {
unset CCACHE_NODIRECT
- ##################################################################
- # Create some code to compile.
cat <<EOF >test.c
-/* test.c */
+// test.c
#include "test1.h"
#include "test2.h"
EOF
cat <<EOF >test3.h
int test3;
EOF
- cat <<EOF >code.c
-/* code.c */
-int test() {}
-EOF
backdate test1.h test2.h test3.h
- $COMPILER -c -Wp,-MD,expected.d test.c
- expected_d_content=`cat expected.d`
+ $UNCACHED_COMPILE -c -Wp,-MD,expected.d test.c
+ $UNCACHED_COMPILE -c -Wp,-MMD,expected_mmd.d test.c
+ rm test.o
+}
+
+SUITE_direct() {
+ # -------------------------------------------------------------------------
+ TEST "Base case"
- $COMPILER -c -Wp,-MMD,expected_mmd.d test.c
- expected_mmd_d_content=`cat expected_mmd.d`
+ $UNCACHED_COMPILE -c -o reference_test.o test.c
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2 # .o + .manifest
+ expect_equal_object_files reference_test.o test.o
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2
+ expect_equal_object_files reference_test.o test.o
+
+ # -------------------------------------------------------------------------
+ TEST "Corrupt manifest file"
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- ##################################################################
- # First compilation is a miss.
- testname="first compilation"
- $CCACHE -z >/dev/null
- $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- ##################################################################
- # Another compilation should now generate a direct hit.
- testname="direct hit"
- $CCACHE -z >/dev/null
- $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
-
- ##################################################################
- # Check that corrupt manifest files are handled and rewritten.
- testname="corrupt manifest file"
- $CCACHE -z >/dev/null
manifest_file=`find $CCACHE_DIR -name '*.manifest'`
rm $manifest_file
touch $manifest_file
- $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 0
- $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 0
-
- ##################################################################
- # Compiling with CCACHE_NODIRECT set should generate a preprocessed hit.
- testname="preprocessed hit"
- $CCACHE -z >/dev/null
- CCACHE_NODIRECT=1 $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 0
-
- ##################################################################
- # Test compilation of a modified include file.
- testname="modified include file"
- $CCACHE -z >/dev/null
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_NODIRECT"
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_NODIRECT=1 $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Modified include file"
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
echo "int test3_2;" >>test3.h
backdate test3.h
- $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- ##################################################################
- # A removed but previously compiled header file should be handled
- # gracefully.
- testname="missing header file"
- $CCACHE -z >/dev/null
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
- mv test1.h test1.h.saved
- mv test3.h test3.h.saved
+ # -------------------------------------------------------------------------
+ TEST "Removed but previously compiled header file"
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ rm test3.h
cat <<EOF >test1.h
-/* No more include of test3.h */
+// No more include of test3.h
int test1;
EOF
backdate test1.h
- $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
- $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
- # Restore
- mv test1.h.saved test1.h
- mv test3.h.saved test3.h
-
- rm -f other.d
+ # -------------------------------------------------------------------------
+ TEST "Calculation of dependency file names"
- ##################################################################
- # Check calculation of dependency file names.
- $CCACHE -Cz >/dev/null
- checkstat 'files in cache' 0
mkdir test.dir
for ext in .obj "" . .foo.bar; do
- testname="dependency file calculation from object file 'test$ext'"
dep_file=test.dir/`echo test$ext | sed 's/\.[^.]*\$//'`.d
- $CCACHE $COMPILER -MD -c test.c -o test.dir/test$ext
+ $CCACHE_COMPILE -MD -c test.c -o test.dir/test$ext
rm -f $dep_file
- $CCACHE $COMPILER -MD -c test.c -o test.dir/test$ext
+ $CCACHE_COMPILE -MD -c test.c -o test.dir/test$ext
if [ ! -f $dep_file ]; then
test_failed "$dep_file missing"
fi
done
- rm -rf test.dir
- checkstat 'files in cache' 12
+ expect_stat 'files in cache' 12
- ##################################################################
- # Check that -Wp,-MD,file.d works.
- testname="-Wp,-MD"
- $CCACHE -z >/dev/null
- $CCACHE $COMPILER -c -Wp,-MD,other.d test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile other.d "$expected_d_content"
- CCACHE_DISABLE=1 $COMPILER -c -Wp,-MD,other.d test.c -o reference_test.o
- compare_file reference_test.o test.o
+ # -------------------------------------------------------------------------
+ TEST "-Wp,-MD"
- rm -f other.d
+ $CCACHE_COMPILE -c -Wp,-MD,other.d test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected.d
- $CCACHE $COMPILER -c -Wp,-MD,other.d test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile other.d "$expected_d_content"
- compare_file reference_test.o test.o
+ $UNCACHED_COMPILE -c -Wp,-MD,other.d test.c -o reference_test.o
+ expect_equal_object_files reference_test.o test.o
rm -f other.d
+ $CCACHE_COMPILE -c -Wp,-MD,other.d test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected.d
+ expect_equal_object_files reference_test.o test.o
+
+ $CCACHE_COMPILE -c -Wp,-MD,different_name.d test.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files different_name.d expected.d
+ expect_equal_object_files reference_test.o test.o
+
+ # -------------------------------------------------------------------------
+ TEST "-Wp,-MMD"
+
+ $CCACHE_COMPILE -c -Wp,-MMD,other.d test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected_mmd.d
+
+ $UNCACHED_COMPILE -c -Wp,-MMD,other.d test.c -o reference_test.o
+ expect_equal_object_files reference_test.o test.o
- $CCACHE $COMPILER -c -Wp,-MD,different_name.d test.c
- checkstat 'cache hit (direct)' 2
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile different_name.d "$expected_d_content"
- compare_file reference_test.o test.o
+ rm -f other.d
+ $CCACHE_COMPILE -c -Wp,-MMD,other.d test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected_mmd.d
+ expect_equal_object_files reference_test.o test.o
+
+ $CCACHE_COMPILE -c -Wp,-MMD,different_name.d test.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files different_name.d expected_mmd.d
+ expect_equal_object_files reference_test.o test.o
+
+ # -------------------------------------------------------------------------
+ TEST "-Wp,-D"
+
+ $CCACHE_COMPILE -c -Wp,-DFOO test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c -DFOO test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-Wp, with multiple arguments"
+
+ # ccache could try to parse and make sense of -Wp, with multiple arguments,
+ # but it currently doesn't, so we have to disable direct mode.
+
+ $CCACHE_COMPILE -c -Wp,-DFOO,-DGOO test.c 2>/dev/null
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c -Wp,-DFOO,-DGOO test.c 2>/dev/null
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Multiple object entries in manifest"
- rm -f different_name.d
+ for i in 0 1 2 3 4; do
+ echo "int test1_$i;" >>test1.h
+ backdate test1.h
+ $CCACHE_COMPILE -c test.c
+ $CCACHE_COMPILE -c test.c
+ done
+ expect_stat 'cache hit (direct)' 5
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 5
- ##################################################################
- # Check that -Wp,-MMD,file.d works.
- testname="-Wp,-MMD"
- $CCACHE -C >/dev/null
- $CCACHE -z >/dev/null
- $CCACHE $COMPILER -c -Wp,-MMD,other.d test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile other.d "$expected_mmd_d_content"
- CCACHE_DISABLE=1 $COMPILER -c -Wp,-MMD,other.d test.c -o reference_test.o
- compare_file reference_test.o test.o
+ # -------------------------------------------------------------------------
+ TEST "-MD"
- rm -f other.d
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
- $CCACHE $COMPILER -c -Wp,-MMD,other.d test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile other.d "$expected_mmd_d_content"
- compare_file reference_test.o test.o
+ $UNCACHED_COMPILE -c -MD test.c -o reference_test.o
+ expect_equal_object_files reference_test.o test.o
- rm -f other.d
+ rm -f test.d
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+ expect_equal_object_files reference_test.o test.o
- $CCACHE $COMPILER -c -Wp,-MMD,different_name.d test.c
- checkstat 'cache hit (direct)' 2
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile different_name.d "$expected_mmd_d_content"
- compare_file reference_test.o test.o
+ # -------------------------------------------------------------------------
+ TEST "-ftest-coverage"
- rm -f different_name.d
+ cat <<EOF >code.c
+int test() { return 0; }
+EOF
- ##################################################################
- # Test some header modifications to get multiple objects in the manifest.
- testname="several objects"
- $CCACHE -z >/dev/null
- for i in 0 1 2 3 4; do
- echo "int test1_$i;" >>test1.h
- backdate test1.h
- $CCACHE $COMPILER -c test.c
- $CCACHE $COMPILER -c test.c
- done
- checkstat 'cache hit (direct)' 5
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 5
+ $CCACHE_COMPILE -c -fprofile-arcs -ftest-coverage code.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ test -r code.gcno || test_failed "code.gcno missing"
- ##################################################################
- # Check that -MD works.
- testname="-MD"
- $CCACHE -z >/dev/null
- $CCACHE $COMPILER -c -MD test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile test.d "$expected_d_content"
- CCACHE_DISABLE=1 $COMPILER -c -MD test.c -o reference_test.o
- compare_file reference_test.o test.o
+ rm code.gcno
- rm -f test.d
+ $CCACHE_COMPILE -c -fprofile-arcs -ftest-coverage code.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ test -r code.gcno || test_failed "code.gcno missing"
- $CCACHE $COMPILER -c -MD test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile test.d "$expected_d_content"
- compare_file reference_test.o test.o
+ # -------------------------------------------------------------------------
+ TEST "Direct mode on cache created by ccache without direct mode support"
- ##################################################################
- # 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.
- testname="direct mode on old cache"
- $CCACHE -z >/dev/null
- $CCACHE -C >/dev/null
- CCACHE_NODIRECT=1 $CCACHE $COMPILER -c -MD test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile test.d "$expected_d_content"
- CCACHE_DISABLE=1 $COMPILER -c -MD test.c -o reference_test.o
- compare_file reference_test.o test.o
+ CCACHE_NODIRECT=1 $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+ $UNCACHED_COMPILE -c -MD test.c -o reference_test.o
+ expect_equal_object_files reference_test.o test.o
rm -f test.d
- CCACHE_NODIRECT=1 $CCACHE $COMPILER -c -MD test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
- checkfile test.d "$expected_d_content"
- compare_file reference_test.o test.o
+ CCACHE_NODIRECT=1 $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+ expect_equal_object_files reference_test.o test.o
rm -f test.d
- $CCACHE $COMPILER -c -MD test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 1
- checkfile test.d "$expected_d_content"
- compare_file reference_test.o test.o
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+ expect_equal_object_files reference_test.o test.o
rm -f test.d
- $CCACHE $COMPILER -c -MD test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 1
- checkfile test.d "$expected_d_content"
- compare_file reference_test.o test.o
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+ expect_equal_object_files reference_test.o test.o
- ##################################################################
- # Check that -MF works.
- testname="-MF"
- $CCACHE -C >/dev/null
- $CCACHE -z >/dev/null
- $CCACHE $COMPILER -c -MD -MF other.d test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile other.d "$expected_d_content"
- CCACHE_DISABLE=1 $COMPILER -c -MD -MF other.d test.c -o reference_test.o
- compare_file reference_test.o test.o
+ # -------------------------------------------------------------------------
+ TEST "-MF"
+
+ $CCACHE_COMPILE -c -MD -MF other.d test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected.d
+ $UNCACHED_COMPILE -c -MD -MF other.d test.c -o reference_test.o
+ expect_equal_object_files reference_test.o test.o
rm -f other.d
- $CCACHE $COMPILER -c -MD -MF other.d test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile other.d "$expected_d_content"
- compare_file reference_test.o test.o
+ $CCACHE_COMPILE -c -MD -MF other.d test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected.d
+ expect_equal_object_files reference_test.o test.o
- $CCACHE $COMPILER -c -MD -MF different_name.d test.c
- checkstat 'cache hit (direct)' 2
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile different_name.d "$expected_d_content"
- compare_file reference_test.o test.o
+ $CCACHE_COMPILE -c -MD -MF different_name.d test.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files different_name.d expected.d
+ expect_equal_object_files reference_test.o test.o
rm -f different_name.d
- $CCACHE $COMPILER -c -MD -MFthird_name.d test.c
- checkstat 'cache hit (direct)' 3
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile third_name.d "$expected_d_content"
- compare_file reference_test.o test.o
+ $CCACHE_COMPILE -c -MD -MFthird_name.d test.c
+ expect_stat 'cache hit (direct)' 3
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files third_name.d expected.d
+ expect_equal_object_files reference_test.o test.o
rm -f third_name.d
- ##################################################################
- # Check that a missing .d file in the cache is handled correctly.
- testname="missing dependency file"
- $CCACHE -z >/dev/null
- $CCACHE -C >/dev/null
+ # -------------------------------------------------------------------------
+ TEST "Missing .d file"
- $CCACHE $COMPILER -c -MD test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile other.d "$expected_d_content"
- CCACHE_DISABLE=1 $COMPILER -c -MD test.c -o reference_test.o
- compare_file reference_test.o test.o
-
- $CCACHE $COMPILER -c -MD test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile other.d "$expected_d_content"
- compare_file reference_test.o test.o
-
- find $CCACHE_DIR -name '*.d' -exec rm -f '{}' \;
-
- $CCACHE $COMPILER -c -MD test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
- checkfile other.d "$expected_d_content"
- compare_file reference_test.o test.o
-
- ##################################################################
- # Check that stderr from both the preprocessor and the compiler is emitted
- # in direct mode too.
- testname="cpp stderr"
- $CCACHE -z >/dev/null
- $CCACHE -C >/dev/null
-cat <<EOF >cpp-warning.c
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+
+ find $CCACHE_DIR -name '*.d' -delete
+
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+
+ # -------------------------------------------------------------------------
+ TEST "stderr from both preprocessor and compiler"
+
+ cat <<EOF >cpp-warning.c
#if FOO
-/* Trigger preprocessor warning about extra token after #endif. */
+// Trigger preprocessor warning about extra token after #endif.
#endif FOO
int stderr(void)
{
- /* Trigger compiler warning by having no return statement. */
+ // Trigger compiler warning by having no return statement.
}
EOF
- $CCACHE $COMPILER -Wall -W -c cpp-warning.c 2>stderr-orig.txt
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ $CCACHE_COMPILE -Wall -W -c cpp-warning.c 2>stderr-orig.txt
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_NODIRECT=1 $CCACHE_COMPILE -Wall -W -c cpp-warning.c 2>stderr-cpp.txt
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_file_content stderr-cpp.txt "`cat stderr-orig.txt`"
+
+ $CCACHE_COMPILE -Wall -W -c cpp-warning.c 2>stderr-mf.txt
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_file_content stderr-mf.txt "`cat stderr-orig.txt`"
+
+ # -------------------------------------------------------------------------
+ TEST "Empty source file"
- CCACHE_NODIRECT=1
- export CCACHE_NODIRECT
- $CCACHE $COMPILER -Wall -W -c cpp-warning.c 2>stderr-cpp.txt
- unset CCACHE_NODIRECT
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
- checkfile stderr-cpp.txt "`cat stderr-orig.txt`"
-
- $CCACHE $COMPILER -Wall -W -c cpp-warning.c 2>stderr-mf.txt
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
- checkfile stderr-mf.txt "`cat stderr-orig.txt`"
-
- ##################################################################
- # Check that it is possible to compile and cache an empty source code file.
- testname="empty source file"
- $CCACHE -Cz >/dev/null
- cp /dev/null empty.c
- $CCACHE $COMPILER -c empty.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- $CCACHE $COMPILER -c empty.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- ##################################################################
- # Check that empty include files are handled as well.
- testname="empty include file"
- $CCACHE -Cz >/dev/null
- cp /dev/null empty.h
+ touch empty.c
+
+ $CCACHE_COMPILE -c empty.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c empty.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Empty include file"
+
+ touch empty.h
cat <<EOF >include_empty.c
#include "empty.h"
EOF
backdate empty.h
- $CCACHE $COMPILER -c include_empty.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- $CCACHE $COMPILER -c include_empty.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- ##################################################################
- # Check that direct mode correctly detects file name/path changes.
- testname="__FILE__ in source file"
- $CCACHE -Cz >/dev/null
+ $CCACHE_COMPILE -c include_empty.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ $CCACHE_COMPILE -c include_empty.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__FILE__ in source file disables direct mode"
+
cat <<EOF >file.c
#define file __FILE__
int test;
EOF
- $CCACHE $COMPILER -c file.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- $CCACHE $COMPILER -c file.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- $CCACHE $COMPILER -c `pwd`/file.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 2
-
- testname="__FILE__ in include file"
- $CCACHE -Cz >/dev/null
+
+ $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c `pwd`/file.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__FILE__ in include file disables direct mode"
+
cat <<EOF >file.h
#define file __FILE__
int test;
cat <<EOF >file_h.c
#include "file.h"
EOF
- $CCACHE $COMPILER -c file_h.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- $CCACHE $COMPILER -c file_h.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+
+ $CCACHE_COMPILE -c file_h.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c file_h.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
mv file_h.c file2_h.c
- $CCACHE $COMPILER -c `pwd`/file2_h.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 2
-
- ##################################################################
- # Check that direct mode ignores __FILE__ if sloppiness is specified.
- testname="__FILE__ in source file, sloppy"
- $CCACHE -Cz >/dev/null
+
+ $CCACHE_COMPILE -c `pwd`/file2_h.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__FILE__ in source file ignored if sloppy"
+
cat <<EOF >file.c
#define file __FILE__
int test;
EOF
- CCACHE_SLOPPINESS="$default_sloppiness file_macro" $CCACHE $COMPILER -c file.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_SLOPPINESS="$default_sloppiness file_macro" $CCACHE $COMPILER -c file.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_SLOPPINESS="$default_sloppiness file_macro" $CCACHE $COMPILER -c `pwd`/file.c
- checkstat 'cache hit (direct)' 2
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- testname="__FILE__ in include file, sloppy"
- $CCACHE -Cz >/dev/null
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c `pwd`/file.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__FILE__ in include file ignored if sloppy"
+
cat <<EOF >file.h
#define file __FILE__
int test;
cat <<EOF >file_h.c
#include "file.h"
EOF
- CCACHE_SLOPPINESS="$default_sloppiness file_macro" $CCACHE $COMPILER -c file_h.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_SLOPPINESS="$default_sloppiness file_macro" $CCACHE $COMPILER -c file_h.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c file_h.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c file_h.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
mv file_h.c file2_h.c
- CCACHE_SLOPPINESS="$default_sloppiness file_macro" $CCACHE $COMPILER -c `pwd`/file2_h.c
- checkstat 'cache hit (direct)' 2
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- ##################################################################
- # Check that we never get direct hits when __TIME__ is used.
- testname="__TIME__ in source file"
- $CCACHE -Cz >/dev/null
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c `pwd`/file2_h.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__TIME__ in source file disables direct mode"
+
cat <<EOF >time.c
#define time __TIME__
int test;
EOF
- $CCACHE $COMPILER -c time.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- $CCACHE $COMPILER -c time.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
- testname="__TIME__ in include time"
- $CCACHE -Cz >/dev/null
+ $CCACHE_COMPILE -c time.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c time.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__TIME__ in include file disables direct mode"
+
cat <<EOF >time.h
#define time __TIME__
int test;
EOF
backdate time.h
+
cat <<EOF >time_h.c
#include "time.h"
EOF
- $CCACHE $COMPILER -c time_h.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- $CCACHE $COMPILER -c time_h.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
-
- ##################################################################
- # Check that direct mode ignores __TIME__ when sloppiness is specified.
- testname="__TIME__ in source file, sloppy"
- $CCACHE -Cz >/dev/null
+
+ $CCACHE_COMPILE -c time_h.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c time_h.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__TIME__ in source file ignored if sloppy"
+
cat <<EOF >time.c
#define time __TIME__
int test;
EOF
- CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER -c time.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER -c time.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- testname="__TIME__ in include time, sloppy"
- $CCACHE -Cz >/dev/null
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE -c time.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE -c time.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__TIME__ in include file ignored if sloppy"
+
cat <<EOF >time.h
#define time __TIME__
int test;
cat <<EOF >time_h.c
#include "time.h"
EOF
- CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER -c time_h.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER -c time_h.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- ##################################################################
- # Check that a too new include file turns off direct mode.
- testname="too new include file"
- $CCACHE -Cz >/dev/null
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE -c time_h.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE -c time_h.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Too new include file disables direct mode"
+
cat <<EOF >new.c
#include "new.h"
EOF
int test;
EOF
touch -t 203801010000 new.h
- $CCACHE $COMPILER -c new.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- $CCACHE $COMPILER -c new.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
-
- ##################################################################
- # Check that include file mtime is ignored when sloppiness is specified.
- testname="too new include file, sloppy"
- $CCACHE -Cz >/dev/null
+
+ $CCACHE_COMPILE -c new.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c new.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "New include file ignored if sloppy"
+
cat <<EOF >new.c
#include "new.h"
EOF
int test;
EOF
touch -t 203801010000 new.h
- CCACHE_SLOPPINESS="$default_sloppiness include_file_mtime" $CCACHE $COMPILER -c new.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_SLOPPINESS="$default_sloppiness include_file_mtime" $CCACHE $COMPILER -c new.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- ##################################################################
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS include_file_mtime" $CCACHE_COMPILE -c new.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS include_file_mtime" $CCACHE_COMPILE -c new.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
# Check that environment variables that affect the preprocessor are taken
# into account.
- testname="environment variables"
- $CCACHE -Cz >/dev/null
+ TEST "CPATH included in hash"
+
rm -rf subdir1 subdir2
mkdir subdir1 subdir2
cat <<EOF >subdir1/foo.h
#include <foo.h>
EOF
backdate subdir1/foo.h subdir2/foo.h
- CPATH=subdir1 $CCACHE $COMPILER -c foo.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CPATH=subdir1 $CCACHE $COMPILER -c foo.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CPATH=subdir2 $CCACHE $COMPILER -c foo.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 2 # subdir2 is part of the preprocessor output
- CPATH=subdir2 $CCACHE $COMPILER -c foo.c
- checkstat 'cache hit (direct)' 2
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 2
-
- testname="comment in strings"
- $CCACHE -Cz >/dev/null
+
+ CPATH=subdir1 $CCACHE_COMPILE -c foo.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CPATH=subdir1 $CCACHE_COMPILE -c foo.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CPATH=subdir2 $CCACHE_COMPILE -c foo.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ CPATH=subdir2 $CCACHE_COMPILE -c foo.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Comment in strings"
+
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
+
+ $CCACHE_COMPILE -c comment.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c comment.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat '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"
- $CCACHE -Cz >/dev/null
+
+ $CCACHE_COMPILE -c comment.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "#line directives with troublesome files"
+
cat <<EOF >strange.c
int foo;
EOF
for x in stdout tty sda hda; do
if [ -b /dev/$x ] || [ -c /dev/$x ]; then
- echo "#line 1 \"/dev/$x\"" >> strange.c
+ echo "#line 1 \"/dev/$x\"" >>strange.c
fi
done
- CCACHE_SLOPPINESS="$default_sloppiness include_file_mtime" $CCACHE $COMPILER -c strange.c
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS include_file_mtime" $CCACHE_COMPILE -c strange.c
+
manifest=`find $CCACHE_DIR -name '*.manifest'`
if [ -n "$manifest" ]; then
data="`$CCACHE --dump-manifest $manifest | egrep '/dev/(stdout|tty|sda|hda'`"
fi
fi
- ##################################################################
- # Test --dump-manifest output.
- testname="--dump-manifest"
- $CCACHE -Cz >/dev/null
- $CCACHE $COMPILER test.c -c -o test.o
+ # -------------------------------------------------------------------------
+ TEST "--dump-manifest"
+
+ $CCACHE_COMPILE test.c -c -o test.o
+
manifest=`find $CCACHE_DIR -name '*.manifest'`
$CCACHE --dump-manifest $manifest >manifest.dump
- if grep 'Hash: e6b009695d072974f2c4d1dd7e7ed4fc' manifest.dump >/dev/null 2>&1 && \
+ if grep 'Hash: d4de2f956b4a386c6660990a7a1ab13f' manifest.dump >/dev/null 2>&1 && \
grep 'Hash: e94ceb9f1b196c387d098a5f1f4fe862' manifest.dump >/dev/null 2>&1 && \
- grep 'Hash: c2f5392dbc7e8ff6138d01608445240a' manifest.dump >/dev/null 2>&1; then
+ grep 'Hash: ba753bebf9b5eb99524bb7447095e2e6' manifest.dump >/dev/null 2>&1; then
: OK
else
- test_failed "unexpected output of --dump-manifest"
+ test_failed "Unexpected output of --dump-manifest"
fi
- ##################################################################
- testname="argument-less -B and -L"
- $CCACHE -Cz > /dev/null
+ # -------------------------------------------------------------------------
+ TEST "Argument-less -B and -L"
+
cat <<EOF >test.c
#include <stdio.h>
int main(void)
}
EOF
- $CCACHE $COMPILER -A -L -DFOO -c test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache miss' 1
- $CCACHE $COMPILER -A -L -DBAR -c test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache miss' 2
+ $CCACHE_COMPILE -B -L -DFOO -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -B -L -DBAR -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_IGNOREHEADERS"
+
+ cat <<EOF >ignore.h
+// We don't want this header in the manifest.
+EOF
+ backdate ignore.h
+ cat <<EOF >ignore.c
+#include "ignore.h"
+int foo;
+EOF
+
+ CCACHE_IGNOREHEADERS="ignore.h" $CCACHE_COMPILE -c ignore.c
+ manifest=`find $CCACHE_DIR -name '*.manifest'`
+ data="`$CCACHE --dump-manifest $manifest | grep ignore.h`"
+ if [ -n "$data" ]; then
+ test_failed "$manifest contained ignored header: $data"
+ fi
}
-basedir_suite() {
- ##################################################################
- # Create some code to compile.
+# =============================================================================
+
+SUITE_basedir_SETUP() {
+ unset CCACHE_NODIRECT
+
mkdir -p dir1/src dir1/include
cat <<EOF >dir1/src/test.c
+#include <stdarg.h>
#include <test.h>
EOF
cat <<EOF >dir1/include/test.h
EOF
cp -r dir1 dir2
backdate dir1/include/test.h dir2/include/test.h
-
- cat <<EOF >stderr.h
-int stderr(void)
-{
- /* Trigger warning by having no return statement. */
}
-EOF
- cat <<EOF >stderr.c
-#include <stderr.h>
-EOF
- backdate stderr.h
- ##################################################################
- # CCACHE_BASEDIR="" and using absolute include path will result in a cache
- # miss.
- testname="empty CCACHE_BASEDIR"
- $CCACHE -z >/dev/null
+SUITE_basedir() {
+ # -------------------------------------------------------------------------
+ TEST "Enabled CCACHE_BASEDIR"
cd dir1
- CCACHE_BASEDIR="" $CCACHE $COMPILER -I`pwd`/include -c src/test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- cd ..
-
- cd dir2
- CCACHE_BASEDIR="" $CCACHE $COMPILER -I`pwd`/include -c src/test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 2
- cd ..
-
- ##################################################################
- # Setting CCACHE_BASEDIR will result in a cache hit because include paths
- # in the preprocessed output are rewritten.
- testname="set CCACHE_BASEDIR"
- $CCACHE -z >/dev/null
- $CCACHE -C >/dev/null
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- ln -s dir1 symlink_to_dir1
- cd symlink_to_dir1
- CCACHE_BASEDIR="`pwd`" $CCACHE $COMPILER -I`pwd`/include -c src/test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- cd ..
-
- cd dir2
- # The space after -I is there to test an extra code path.
- CCACHE_BASEDIR="`pwd`" $CCACHE $COMPILER -I `pwd`/include -c src/test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
- cd ..
-
- ##################################################################
- # Setting CCACHE_BASEDIR will result in a cache hit because -I arguments
- # are rewritten, as are the paths stored in the manifest.
- testname="set CCACHE_BASEDIR, direct lookup"
- $CCACHE -z >/dev/null
- $CCACHE -C >/dev/null
- unset CCACHE_NODIRECT
+ cd ../dir2
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -c src/test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Disabled (default) CCACHE_BASEDIR"
cd dir1
- CCACHE_BASEDIR="`pwd`" $CCACHE $COMPILER -I`pwd`/include -c src/test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- cd ..
-
- cd dir2
- CCACHE_BASEDIR="`pwd`" $CCACHE $COMPILER -I`pwd`/include -c src/test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- cd ..
-
- ##################################################################
- # CCACHE_BASEDIR="" is the default.
- testname="default CCACHE_BASEDIR"
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # CCACHE_BASEDIR="" is the default:
+ $CCACHE_COMPILE -I`pwd`/include -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Path normalization"
+
cd dir1
- $CCACHE -z >/dev/null
- $CCACHE $COMPILER -I`pwd`/include -c src/test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- cd ..
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- ##################################################################
# Rewriting triggered by CCACHE_BASEDIR should handle paths with multiple
- # slashes correctly.
- testname="path normalization"
- cd dir1
- $CCACHE -z >/dev/null
- CCACHE_BASEDIR=`pwd` $CCACHE $COMPILER -I`pwd`//include -c `pwd`//src/test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
- cd ..
-
- ##################################################################
- # Check that rewriting triggered by CCACHE_BASEDIR also affects stderr.
- testname="stderr"
- $CCACHE -z >/dev/null
- CCACHE_BASEDIR=`pwd` $CCACHE $COMPILER -Wall -W -I`pwd` -c `pwd`/stderr.c -o `pwd`/stderr.o 2>stderr.txt
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ # slashes correctly:
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -I`pwd`//include -c `pwd`//src/test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Rewriting in stderr"
+
+ cat <<EOF >stderr.h
+int stderr(void)
+{
+ // Trigger warning by having no return statement.
+}
+EOF
+ backdate stderr.h
+ cat <<EOF >stderr.c
+#include <stderr.h>
+EOF
+
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -Wall -W -I`pwd` -c `pwd`/stderr.c -o `pwd`/stderr.o 2>stderr.txt
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
if grep `pwd` stderr.txt >/dev/null 2>&1; then
test_failed "Base dir (`pwd`) found in stderr:\n`cat stderr.txt`"
fi
- CCACHE_BASEDIR=`pwd` $CCACHE $COMPILER -Wall -W -I`pwd` -c `pwd`/stderr.c -o `pwd`/stderr.o 2>stderr.txt
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -Wall -W -I`pwd` -c `pwd`/stderr.c -o `pwd`/stderr.o 2>stderr.txt
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
if grep `pwd` stderr.txt >/dev/null 2>&1; then
test_failed "Base dir (`pwd`) found in stderr:\n`cat stderr.txt`"
fi
- ##################################################################
- # Check that -MF, -MQ and -MT arguments with absolute paths are rewritten
- # to relative.
- testname="-MF/-MQ/-MT with absolute paths"
+ # -------------------------------------------------------------------------
+ TEST "-MF/-MQ/-MT with absolute paths"
+
for option in MF "MF " MQ "MQ " MT "MT "; do
- $CCACHE -Cz >/dev/null
+ clear_cache
cd dir1
- CCACHE_BASEDIR="`pwd`" $CCACHE $COMPILER -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
cd ..
cd dir2
- CCACHE_BASEDIR="`pwd`" $CCACHE $COMPILER -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
cd ..
done
- ##################################################################
- # Check that clang's --serialize-diagnostics arguments with absolute paths
- # are rewritten to relative.
- if [ $COMPILER_TYPE_CLANG -eq 1 ]; then
- testname="serialize-diagnostics"
- $CCACHE -Cz >/dev/null
+ # -------------------------------------------------------------------------
+ # When BASEDIR is set to /, check that -MF, -MQ and -MT arguments with
+ # absolute paths are rewritten to relative and that the dependency file
+ # only contains relative paths.
+ TEST "-MF/-MQ/-MT with absolute paths and BASEDIR set to /"
+
+ for option in MF "MF " MQ "MQ " MT "MT "; do
+ clear_cache
cd dir1
- CCACHE_BASEDIR=`pwd` $CCACHE $COMPILER -w -MD -MF `pwd`/test.d -I`pwd`/include --serialize-diagnostics `pwd`/test.dia -c src/test.c -o `pwd`/test.o
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkstat 'files in cache' 4
+ CCACHE_BASEDIR="/" $CCACHE_COMPILE -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ # Check that there is no absolute path in the dependency file:
+ while read line; do
+ for file in $line; do
+ case $file in /*)
+ test_failed "Absolute file path '$file' found in dependency file '`pwd`/test.d'"
+ esac
+ done
+ done <test.d
cd ..
cd dir2
- CCACHE_BASEDIR=`pwd` $CCACHE $COMPILER -w -MD -MF `pwd`/test.d -I`pwd`/include --serialize-diagnostics `pwd`/test.dia -c src/test.c -o `pwd`/test.o
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkstat 'files in cache' 4
+ CCACHE_BASEDIR="/" $CCACHE_COMPILE -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
cd ..
- fi
+ done
}
-compression_suite() {
- ##################################################################
- # Create some code to compile.
- cat <<EOF >test.c
-int test;
-EOF
+# =============================================================================
+
+SUITE_compression_SETUP() {
+ generate_code 1 test.c
+}
+
+SUITE_compression() {
+ # -------------------------------------------------------------------------
+ TEST "Hash sum equal for compressed and uncompressed files"
+
+ CCACHE_COMPRESS=1 $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_COMPRESS=1 $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
- ##################################################################
- # Check that compressed and uncompressed files get the same hash sum.
- testname="compression hash sum"
- CCACHE_COMPRESS=1 $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+}
- CCACHE_COMPRESS=1 $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
+# =============================================================================
- $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 1
+SUITE_readonly_SETUP() {
+ generate_code 1 test.c
+ generate_code 2 test2.c
}
-readonly_suite() {
- ##################################################################
- # Create some code to compile.
- echo "int test;" >test.c
- echo "int test2;" >test2.c
+SUITE_readonly() {
+ # -------------------------------------------------------------------------
+ TEST "Cache hit"
# Cache a compilation.
- $CCACHE $COMPILER -c test.c -o test.o
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- # Make the cache readonly
- # Check that readonly mode finds the result.
- testname="cache hit"
- rm -f test.o test2.o
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ rm test.o
+
+ # Make the cache read-only.
chmod -R a-w $CCACHE_DIR
- CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp CCACHE_PREFIX=false $CCACHE $COMPILER -c test.c -o test.o >/dev/null 2>&1
+
+ # Check that read-only mode finds the cached result.
+ CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp CCACHE_PREFIX=false $CCACHE_COMPILE -c test.c
status1=$?
+
# Check that fallback to the real compiler works for a cache miss.
- CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp $CCACHE $COMPILER -c test2.c -o test2.o >/dev/null 2>&1
+ CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp $CCACHE_COMPILE -c test2.c
status2=$?
- chmod -R a+w $CCACHE_DIR
+
+ # Leave test dir a nice state after test failure.
+ chmod -R +w $CCACHE_DIR
+
if [ $status1 -ne 0 ]; then
- test_failed "failure when compiling test.c readonly"
+ test_failed "Failure when compiling test.c read-only"
fi
if [ $status2 -ne 0 ]; then
- test_failed "failure when compiling test2.c readonly"
+ test_failed "Failure when compiling test2.c read-only"
fi
if [ ! -f test.o ]; then
test_failed "test.o missing"
test_failed "test2.o missing"
fi
- # Check that readonly mode doesn't try to store new results.
- testname="cache miss"
- files_before=`find $CCACHE_DIR -type f | wc -l`
- CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp $CCACHE $COMPILER -c test2.c -o test2.o
- if [ $? -ne 0 ]; then
- test_failed "failure when compiling test2.c readonly"
- fi
- if [ ! -f test2.o ]; then
- test_failed "test2.o missing"
- fi
- files_after=`find $CCACHE_DIR -type f | wc -l`
- if [ $files_before -ne $files_after ]; then
- test_failed "readonly mode stored files in the cache"
- fi
+ # -------------------------------------------------------------------------
+ TEST "Cache miss"
- # Check that readonly mode and direct mode works.
- unset CCACHE_NODIRECT
- files_before=`find $CCACHE_DIR -type f | wc -l`
- CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp $CCACHE $COMPILER -c test.c -o test.o
- CCACHE_NODIRECT=1
- export CCACHE_NODIRECT
+ # Check that read-only mode doesn't try to store new results.
+ CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp $CCACHE_COMPILE -c test.c
if [ $? -ne 0 ]; then
- test_failed "failure when compiling test2.c readonly"
+ test_failed "Failure when compiling test2.c read-only"
fi
- files_after=`find $CCACHE_DIR -type f | wc -l`
- if [ $files_before -ne $files_after ]; then
- test_failed "readonly mode + direct mode stored files in the cache"
+ if [ -d $CCACHE_DIR ]; then
+ test_failed "ccache dir was created"
fi
- ##################################################################
-}
+ # -------------------------------------------------------------------------
+ # Check that read-only mode and direct mode work together.
+ TEST "Cache hit, direct"
-readonly_direct_suite() {
- unset CCACHE_NODIRECT
+ # Cache a compilation.
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ rm test.o
- ##################################################################
- # Create some code to compile.
- echo "int test;" >test.c
+ # Make the cache read-only.
+ chmod -R a-w $CCACHE_DIR
- # Cache a compilation.
- testname="fill cache"
- $CCACHE $COMPILER -c test.c -o test.o
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- # Check that "readonly direct" mode gets a direct hit.
- testname="direct hit"
- CCACHE_READONLY_DIRECT=1 $CCACHE $COMPILER -c test.c -o test.o
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- # Check that "readonly direct" mode doesn't get a preprocessed hit.
- testname="preprocessed miss"
- CCACHE_READONLY_DIRECT=1 $CCACHE $COMPILER -DFOO -c test.c -o test.o
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-}
+ # Direct mode should work:
+ files_before=`find $CCACHE_DIR -type f | wc -l`
+ CCACHE_DIRECT=1 CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp $CCACHE_COMPILE -c test.c
+ files_after=`find $CCACHE_DIR -type f | wc -l`
-extrafiles_suite() {
- ##################################################################
- # Create some code to compile.
- cat <<EOF >test.c
-int test;
-EOF
- echo a >a
- echo b >b
+ # Leave test dir a nice state after test failure.
+ chmod -R +w $CCACHE_DIR
+
+ if [ $? -ne 0 ]; then
+ test_failed "Failure when compiling test.c read-only"
+ fi
+ if [ $files_after -ne $files_before ]; then
+ test_failed "Read-only mode + direct mode stored files in the cache"
+ fi
+}
- ##################################################################
- # Test the CCACHE_EXTRAFILES feature.
+# =============================================================================
- testname="cache hit"
- $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+SUITE_readonly_direct_SETUP() {
+ unset CCACHE_NODIRECT
+
+ generate_code 1 test.c
+}
- testname="cache miss"
- $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
+SUITE_readonly_direct() {
+ # -------------------------------------------------------------------------
+ TEST "Direct hit"
- testname="cache miss a b"
- CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 2
+ $CCACHE_COMPILE -c test.c -o test.o
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- testname="cache hit a b"
- CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 2
+ CCACHE_READONLY_DIRECT=1 $CCACHE_COMPILE -c test.c -o test.o
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- testname="cache miss a b2"
- echo b2 >b
- CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 3
-
- testname="cache hit a b2"
- CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (preprocessed)' 3
- checkstat 'cache miss' 3
-
- testname="cache miss doesntexist"
- CCACHE_EXTRAFILES="doesntexist" $CCACHE $COMPILER -c test.c
- checkstat 'cache hit (preprocessed)' 3
- checkstat 'cache miss' 3
- checkstat 'error hashing extra file' 1
+ # -------------------------------------------------------------------------
+ TEST "Direct miss doesn't lead to preprocessed hit"
+
+ $CCACHE_COMPILE -c test.c -o test.o
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_READONLY_DIRECT=1 $CCACHE_COMPILE -DFOO -c test.c -o test.o
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
}
-prepare_cleanup_test() {
- dir=$1
+# =============================================================================
+
+prepare_cleanup_test_dir() {
+ local dir=$1
+
rm -rf $dir
mkdir -p $dir
- i=0
- while [ $i -lt 10 ]; do
+ for i in $(seq 0 9); do
printf '%4017s' '' | tr ' ' 'A' >$dir/result$i-4017.o
touch $dir/result$i-4017.stderr
touch $dir/result$i-4017.d
if [ $i -gt 5 ]; then
backdate $dir/result$i-4017.stderr
fi
- i=`expr $i + 1`
done
# NUMFILES: 30, TOTALSIZE: 40 KiB, MAXFILES: 0, MAXSIZE: 0
echo "0 0 0 0 0 0 0 0 0 0 0 30 40 0 0" >$dir/stats
}
-cleanup_suite() {
- testname="clear"
- prepare_cleanup_test $CCACHE_DIR/a
- $CCACHE -C >/dev/null
- checkfilecount 0 '*.o' $CCACHE_DIR
- checkfilecount 0 '*.d' $CCACHE_DIR
- checkfilecount 0 '*.stderr' $CCACHE_DIR
- checkstat 'files in cache' 0
+SUITE_cleanup() {
+ # -------------------------------------------------------------------------
+ TEST "Clear cache"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
- testname="forced cleanup, no limits"
$CCACHE -C >/dev/null
- prepare_cleanup_test $CCACHE_DIR/a
+ expect_file_count 0 '*.o' $CCACHE_DIR
+ expect_file_count 0 '*.d' $CCACHE_DIR
+ expect_file_count 0 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 0
+ expect_stat 'cleanups performed' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Forced cache cleanup, no limits"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
$CCACHE -F 0 -M 0 >/dev/null
$CCACHE -c >/dev/null
- checkfilecount 10 '*.o' $CCACHE_DIR
- checkfilecount 10 '*.d' $CCACHE_DIR
- checkfilecount 10 '*.stderr' $CCACHE_DIR
- checkstat 'files in cache' 30
+ expect_file_count 10 '*.o' $CCACHE_DIR
+ expect_file_count 10 '*.d' $CCACHE_DIR
+ expect_file_count 10 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 30
+ expect_stat 'cleanups performed' 0
+
+ # -------------------------------------------------------------------------
+ TEST "Forced cache cleanup, file limit"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
- testname="forced cleanup, file limit"
- $CCACHE -C >/dev/null
- prepare_cleanup_test $CCACHE_DIR/a
# (9/10) * 30 * 16 = 432
$CCACHE -F 432 -M 0 >/dev/null
$CCACHE -c >/dev/null
# floor(0.8 * 9) = 7
- checkfilecount 7 '*.o' $CCACHE_DIR
- checkfilecount 7 '*.d' $CCACHE_DIR
- checkfilecount 7 '*.stderr' $CCACHE_DIR
- checkstat 'files in cache' 21
+ expect_file_count 7 '*.o' $CCACHE_DIR
+ expect_file_count 7 '*.d' $CCACHE_DIR
+ expect_file_count 7 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 21
+ expect_stat 'cleanups performed' 1
for i in 0 1 2 3 4 5 9; do
file=$CCACHE_DIR/a/result$i-4017.o
if [ ! -f $file ]; then
fi
done
- # Warning: this test is known to fail on filesystems that have
- # unusual block sizes, including ecryptfs. The workaround is
- # to place the test directory elsewhere:
+ # -------------------------------------------------------------------------
+ TEST "Forced cache cleanup, size limit"
+
+ # NOTE: This test is known to fail on filesystems that have unusual block
+ # sizes, including ecryptfs. The workaround is to place the test directory
+ # elsewhere:
+ #
# cd /tmp
# CCACHE=$DIR/ccache $DIR/test.sh
- testname="forced cleanup, size limit"
- $CCACHE -C >/dev/null
- prepare_cleanup_test $CCACHE_DIR/a
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
# (4/10) * 10 * 4 * 16 = 256
$CCACHE -F 0 -M 256K >/dev/null
$CCACHE -c >/dev/null
# floor(0.8 * 4) = 3
- checkfilecount 3 '*.o' $CCACHE_DIR
- checkfilecount 3 '*.d' $CCACHE_DIR
- checkfilecount 3 '*.stderr' $CCACHE_DIR
- checkstat 'files in cache' 9
+ expect_file_count 3 '*.o' $CCACHE_DIR
+ expect_file_count 3 '*.d' $CCACHE_DIR
+ expect_file_count 3 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 9
+ expect_stat 'cleanups performed' 1
for i in 3 4 5; do
file=$CCACHE_DIR/a/result$i-4017.o
if [ ! -f $file ]; then
fi
done
- testname="autocleanup"
- $CCACHE -C >/dev/null
+ # -------------------------------------------------------------------------
+ TEST "Automatic cache cleanup"
+
for x in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
- prepare_cleanup_test $CCACHE_DIR/$x
+ prepare_cleanup_test_dir $CCACHE_DIR/$x
done
+
# (9/10) * 30 * 16 = 432
$CCACHE -F 432 -M 0 >/dev/null
+ expect_file_count 160 '*.o' $CCACHE_DIR
+ expect_file_count 160 '*.d' $CCACHE_DIR
+ expect_file_count 160 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 480
+
touch empty.c
- checkfilecount 160 '*.o' $CCACHE_DIR
- checkfilecount 160 '*.d' $CCACHE_DIR
- checkfilecount 160 '*.stderr' $CCACHE_DIR
- checkstat 'files in cache' 480
- $CCACHE $COMPILER -c empty.c -o empty.o
+ $CCACHE_COMPILE -c empty.c -o empty.o
# floor(0.8 * 9) = 7
- checkfilecount 157 '*.o' $CCACHE_DIR
- checkfilecount 156 '*.d' $CCACHE_DIR
- checkfilecount 156 '*.stderr' $CCACHE_DIR
- checkstat 'files in cache' 469
+ expect_file_count 157 '*.o' $CCACHE_DIR
+ expect_file_count 156 '*.d' $CCACHE_DIR
+ expect_file_count 156 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 469
+ expect_stat 'cleanups performed' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Cleanup of sibling files"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
- testname="sibling cleanup"
- $CCACHE -C >/dev/null
- prepare_cleanup_test $CCACHE_DIR/a
# (9/10) * 30 * 16 = 432
$CCACHE -F 432 -M 0 >/dev/null
backdate $CCACHE_DIR/a/result2-4017.stderr
$CCACHE -c >/dev/null
# floor(0.8 * 9) = 7
- checkfilecount 7 '*.o' $CCACHE_DIR
- checkfilecount 7 '*.d' $CCACHE_DIR
- checkfilecount 7 '*.stderr' $CCACHE_DIR
- checkstat 'files in cache' 21
+ expect_file_count 7 '*.o' $CCACHE_DIR
+ expect_file_count 7 '*.d' $CCACHE_DIR
+ expect_file_count 7 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 21
for i in 0 1 3 4 5 8 9; do
file=$CCACHE_DIR/a/result$i-4017.o
if [ ! -f $file ]; then
fi
done
- testname="new unknown file"
- $CCACHE -C >/dev/null
- prepare_cleanup_test $CCACHE_DIR/a
+ # -------------------------------------------------------------------------
+ TEST "No cleanup of new unknown file"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
touch $CCACHE_DIR/a/abcd.unknown
$CCACHE -F 0 -M 0 -c >/dev/null # update counters
- checkstat 'files in cache' 31
+ expect_stat 'files in cache' 31
# (9/10) * 30 * 16 = 432
$CCACHE -F 432 -M 0 >/dev/null
$CCACHE -c >/dev/null
if [ ! -f $CCACHE_DIR/a/abcd.unknown ]; then
test_failed "$CCACHE_DIR/a/abcd.unknown removed"
fi
- checkstat 'files in cache' 19
+ expect_stat 'files in cache' 19
- testname="old unknown file"
- $CCACHE -C >/dev/null
- prepare_cleanup_test $CCACHE_DIR/a
+ # -------------------------------------------------------------------------
+ TEST "Cleanup of old unknown file"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
# (9/10) * 30 * 16 = 432
$CCACHE -F 432 -M 0 >/dev/null
touch $CCACHE_DIR/a/abcd.unknown
test_failed "$CCACHE_DIR/a/abcd.unknown not removed"
fi
- testname="cleanup of tmp files"
- $CCACHE -C >/dev/null
+ # -------------------------------------------------------------------------
+ TEST "Cleanup of tmp file"
+
+ mkdir -p $CCACHE_DIR/a
touch $CCACHE_DIR/a/abcd.tmp.efgh
$CCACHE -c >/dev/null # update counters
- checkstat 'files in cache' 1
+ expect_stat 'files in cache' 1
backdate $CCACHE_DIR/a/abcd.tmp.efgh
$CCACHE -c >/dev/null
if [ -f $CCACHE_DIR/a/abcd.tmp.efgh ]; then
test_failed "$CCACHE_DIR/a/abcd.tmp.unknown not removed"
fi
- checkstat 'files in cache' 0
+ expect_stat 'files in cache' 0
+
+ # -------------------------------------------------------------------------
+ TEST "No cleanup of .nfs* files"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
- testname="ignore .nfs* files"
- prepare_cleanup_test $CCACHE_DIR/a
touch $CCACHE_DIR/a/.nfs0123456789
$CCACHE -F 0 -M 0 >/dev/null
$CCACHE -c >/dev/null
- checkfilecount 1 '.nfs*' $CCACHE_DIR
- checkstat 'files in cache' 30
+ expect_file_count 1 '.nfs*' $CCACHE_DIR
+ expect_stat 'files in cache' 30
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_LIMIT_MULTIPLE"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
+ # (1/1) * 30 * 16 = 480
+ $CCACHE -F 480 >/dev/null
+ CCACHE_LIMIT_MULTIPLE=0.5 $CCACHE -c >/dev/null
+ expect_stat 'files in cache' 15
+}
+
+# =============================================================================
+
+SUITE_pch_PROBE() {
+ touch pch.h
+ if ! $UNCACHED_COMPILE $SYSROOT -fpch-preprocess pch.h 2>/dev/null \
+ || [ ! -f pch.h.gch ]; then
+ echo "compiler ($($COMPILER --version | head -1)) doesn't support precompiled headers"
+ fi
}
-pch_suite() {
+SUITE_pch_SETUP() {
unset CCACHE_NODIRECT
cat <<EOF >pch.c
cat <<EOF >pch.h
#include <stdlib.h>
EOF
+ backdate pch.h
cat <<EOF >pch2.c
int main()
{
return 0;
}
EOF
+}
- if $COMPILER $SYSROOT -fpch-preprocess pch.h 2>/dev/null && [ -f pch.h.gch ] && $COMPILER $SYSROOT pch.c -o pch; then
- rm pch.h.gch
- else
- echo "Compiler (`$COMPILER --version | head -1`) doesn't support precompiled headers -- not running pch test"
- return
- fi
-
- # clang and gcc handle precompiled headers similarly, but gcc is much more
- # forgiving with precompiled headers. Both gcc and clang keep an absolute
- # path reference to the original file except that clang uses that reference
- # to validate the pch and gcc ignores the reference. Also, clang has an
- # additional feature: pre-tokenized headers. For these reasons clang should
- # be tested separately than gcc. clang can only use pch or pth headers on
- # the command line and not as an #include statement inside a source file.
-
- if [ $COMPILER_TYPE_CLANG -eq 1 ]; then
- clang_pch_suite
+SUITE_pch() {
+ # Clang and GCC handle precompiled headers similarly, but GCC is much more
+ # forgiving with precompiled headers. Both GCC and Clang keep an absolute
+ # path reference to the original file except that Clang uses that reference
+ # to validate the pch and GCC ignores the reference. Also, Clang has an
+ # additional feature: pre-tokenized headers. For these reasons, Clang
+ # should be tested differently from GCC. Clang can only use pch or pth
+ # headers on the command line and not as an #include statement inside a
+ # source file.
+
+ if $COMPILER_TYPE_CLANG; then
+ pch_suite_clang
else
- gcc_pch_suite
+ pch_suite_gcc
fi
}
-gcc_pch_suite() {
- ##################################################################
- # Tests for creating a .gch without opt-in.
+pch_suite_gcc() {
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, -c, no -o, without opt-in"
- backdate pch.h
+ $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat "can't use precompiled header" 1
- testname="create .gch, -c, no -o, without opt-in"
- $CCACHE -zC >/dev/null
- $CCACHE $COMPILER $SYSROOT -c pch.h
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
- checkstat "can't use precompiled header" 1
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, no -c, -o, without opt-in"
- testname="create .gch, no -c, -o, without opt-in"
- $CCACHE -Cz >/dev/null
- $CCACHE $COMPILER pch.h -o pch.gch
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
- checkstat "can't use precompiled header" 1
+ $CCACHE_COMPILE pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat "can't use precompiled header" 1
- ##################################################################
- # Tests for creating a .gch with opt-in.
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, -c, no -o, with opt-in"
- backdate pch.h
+ CCACHE_SLOPPINESS=pch_defines $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ rm pch.h.gch
- testname="create .gch, -c, no -o, with opt-in"
- $CCACHE -zC >/dev/null
- CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE $COMPILER $SYSROOT -c pch.h
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- rm -f pch.h.gch
- CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE $COMPILER $SYSROOT -c pch.h
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ CCACHE_SLOPPINESS=pch_defines $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
if [ ! -f pch.h.gch ]; then
test_failed "pch.h.gch missing"
fi
- testname="create .gch, no -c, -o, with opt-in"
- $CCACHE -Cz >/dev/null
- CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE $COMPILER $SYSROOT pch.h -o pch.gch
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE $COMPILER $SYSROOT pch.h -o pch.gch
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, no -c, -o, with opt-in"
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
if [ ! -f pch.gch ]; then
test_failed "pch.gch missing"
fi
- rm pch.gch
- ##################################################################
- # Tests for using a .gch.
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, no -fpch-preprocess, #include"
- rm -f pch.h
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
backdate pch.h.gch
+ rm pch.h
- testname="no -fpch-preprocess, #include"
- $CCACHE -Cz >/dev/null
- $CCACHE $COMPILER $SYSROOT -c pch.c 2>/dev/null
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
+ $CCACHE_COMPILE $SYSROOT -c pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
# Preprocessor error because GCC can't find the real include file when
# trying to preprocess:
- checkstat 'preprocessor error' 1
+ expect_stat 'preprocessor error' 1
- testname="no -fpch-preprocess, -include, no sloppiness"
- $CCACHE -Cz >/dev/null
- $CCACHE $COMPILER $SYSROOT -c -include pch.h pch2.c 2>/dev/null
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, no -fpch-preprocess, -include, no sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
# Must enable sloppy time macros:
- checkstat "can't use precompiled header" 1
+ expect_stat "can't use precompiled header" 1
- testname="no -fpch-preprocess, -include"
- $CCACHE -Cz >/dev/null
- CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER $SYSROOT -c -include pch.h pch2.c 2>/dev/null
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER $SYSROOT -c -include pch.h pch2.c 2>/dev/null
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- testname="-fpch-preprocess, #include, no sloppiness"
- $CCACHE -Cz >/dev/null
- $CCACHE $COMPILER $SYSROOT -c -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, no -fpch-preprocess, -include, sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, -fpch-preprocess, #include, no sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
# Must enable sloppy time macros:
- checkstat "can't use precompiled header" 1
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, -fpch-preprocess, #include, sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, -fpch-preprocess, #include, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- testname="-fpch-preprocess, #include, sloppiness"
- $CCACHE -Cz >/dev/null
- CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER $SYSROOT -c -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER $SYSROOT -c -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- testname="-fpch-preprocess, #include, file changed"
echo "updated" >>pch.h.gch # GCC seems to cope with this...
backdate pch.h.gch
- CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER $SYSROOT -c -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 2
- testname="preprocessor mode"
- $CCACHE -Cz >/dev/null
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER $SYSROOT -c -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER $SYSROOT -c -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
-
- testname="preprocessor mode, file changed"
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, preprocessor mode"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, preprocessor mode, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
echo "updated" >>pch.h.gch # GCC seems to cope with this...
backdate pch.h.gch
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER $SYSROOT -c -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 2
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$default_sloppiness pch_defines time_macros" $CCACHE $COMPILER $SYSROOT -c -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 2
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
}
-clang_pch_suite() {
- ##################################################################
- # Tests for creating a .gch.
+pch_suite_clang() {
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, -c, no -o, without opt-in"
- backdate pch.h
+ $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, no -c, -o, without opt-in"
+
+ $CCACHE_COMPILE pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat "can't use precompiled header" 1
- testname="create .gch, -c, no -o"
- $CCACHE -zC >/dev/null
- $CCACHE $COMPILER $SYSROOT -c pch.h
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- rm -f pch.h.gch
- $CCACHE $COMPILER $SYSROOT -c pch.h
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, -c, no -o, with opt-in"
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ rm pch.h.gch
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
if [ ! -f pch.h.gch ]; then
test_failed "pch.h.gch missing"
fi
- testname="create .gch, no -c, -o"
- $CCACHE -Cz >/dev/null
- $CCACHE $COMPILER $SYSROOT pch.h -o pch.gch
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- $CCACHE $COMPILER $SYSROOT pch.h -o pch.gch
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, no -c, -o, with opt-in"
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
if [ ! -f pch.gch ]; then
test_failed "pch.gch missing"
fi
- rm pch.gch
- ##################################################################
- # Tests for using a .gch.
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, no -fpch-preprocess, -include, no sloppiness"
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
backdate pch.h.gch
- testname="gch, no -fpch-preprocess, -include, no sloppy time macros"
- $CCACHE -Cz >/dev/null
- $CCACHE $COMPILER $SYSROOT -c -include pch.h pch2.c 2>/dev/null
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
+ $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c 2>/dev/null
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
# Must enable sloppy time macros:
- checkstat "can't use precompiled header" 1
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, no -fpch-preprocess, -include, sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, -fpch-preprocess, -include, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- testname="gch, no -fpch-preprocess, -include, sloppy time macros"
- $CCACHE -Cz >/dev/null
- CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h pch2.c 2>/dev/null
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h pch2.c 2>/dev/null
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- testname="gch, -fpch-preprocess, -include, file changed"
echo "updated" >>pch.h.gch # clang seems to cope with this...
backdate pch.h.gch
- CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 2
- testname="gch, preprocessor mode"
- $CCACHE -Cz >/dev/null
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
-
- testname="gch, preprocessor mode, file changed"
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, preprocessor mode"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, preprocessor mode, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
echo "updated" >>pch.h.gch # clang seems to cope with this...
backdate pch.h.gch
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 2
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 2
- rm pch.h.gch
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
- ##################################################################
- # Tests for creating a .pth.
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
- backdate pch.h
+ # -------------------------------------------------------------------------
+ TEST "Create .pth, -c, -o"
- testname="create .pth, -c, -o"
- $CCACHE -zC >/dev/null
- $CCACHE $COMPILER $SYSROOT -c pch.h -o pch.h.pth
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
rm -f pch.h.pth
- $CCACHE $COMPILER $SYSROOT -c pch.h -o pch.h.pth
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
if [ ! -f pch.h.pth ]; then
test_failed "pch.h.pth missing"
fi
- ##################################################################
- # Tests for using a .pth.
+ # -------------------------------------------------------------------------
+ TEST "Use .pth, no -fpch-preprocess, -include, no sloppiness"
+ $UNCACHED_COMPILE $SYSROOT -c pch.h -o pch.h.pth
backdate pch.h.pth
- testname="pth, no -fpch-preprocess, -include, no sloppy time macros"
- $CCACHE -Cz >/dev/null
- $CCACHE $COMPILER $SYSROOT -c -include pch.h pch2.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 0
+ $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
# Must enable sloppy time macros:
- checkstat "can't use precompiled header" 1
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .pth, no -fpch-preprocess, -include, sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ backdate pch.h.pth
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .pth, -fpch-preprocess, -include, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ backdate pch.h.pth
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- testname="pth, no -fpch-preprocess, -include, sloppy time macros"
- $CCACHE -Cz >/dev/null
- CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h pch2.c 2>/dev/null
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h pch2.c 2>/dev/null
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
-
- testname="pth, -fpch-preprocess, -include, file changed"
echo "updated" >>pch.h.pth # clang seems to cope with this...
backdate pch.h.pth
- CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 1
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 2
- testname="pth, preprocessor mode"
- $CCACHE -Cz >/dev/null
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
-
- testname="pth, preprocessor mode, file changed"
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Use .pth, preprocessor mode"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ backdate pch.h.pth
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .pth, preprocessor mode, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ backdate pch.h.pth
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
echo "updated" >>pch.h.pth # clang seems to cope with this...
backdate pch.h.pth
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 2
- CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER $SYSROOT -c -include pch.h -fpch-preprocess pch.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 2
- checkstat 'cache miss' 2
-
- rm pch.h.pth
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
}
-upgrade_suite() {
- testname="keep maxfiles and maxsize settings"
- rm -rf $CCACHE_DIR $CCACHE_CONFIGPATH
+# =============================================================================
+
+SUITE_upgrade() {
+ TEST "Keep maxfiles and maxsize settings"
+
+ rm $CCACHE_CONFIGPATH
mkdir -p $CCACHE_DIR/0
echo "0 0 0 0 0 0 0 0 0 0 0 0 0 2000 131072" >$CCACHE_DIR/0/stats
- checkstat 'max files' 32000
- checkstat 'max cache size' '2.1 GB'
+ expect_stat 'max files' 32000
+ expect_stat 'max cache size' '2.1 GB'
}
-prefix_suite() {
- testname="prefix"
- $CCACHE -Cz >/dev/null
- rm -f prefix.result
- cat <<'EOF' >prefix-a
-#!/bin/sh
-echo a >>prefix.result
-exec "$@"
-EOF
- cat <<'EOF' >prefix-b
-#!/bin/sh
-echo b >>prefix.result
-exec "$@"
-EOF
- chmod +x prefix-a prefix-b
- cat <<'EOF' >file.c
-int foo;
-EOF
- PATH=.:$PATH CCACHE_PREFIX="prefix-a prefix-b" $CCACHE $COMPILER -c file.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- checkfile prefix.result "a
-b"
- PATH=.:$PATH CCACHE_PREFIX="prefix-a prefix-b" $CCACHE $COMPILER -c file.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
- checkfile prefix.result "a
-b"
-}
+# =============================================================================
-buggy_cpp_suite() {
- testname="buggy_cpp"
- $CCACHE -Cz >/dev/null
- cat >buggy-cpp <<EOF
-#!/bin/sh
-CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
-export CCACHE_DISABLE
-if echo "\$*" | grep -- -D >/dev/null; then
- $COMPILER "\$@"
-else
- # mistreat the preprocessor output in the same way as gcc6 does
- $COMPILER "\$@" |
- sed -e '/^# 1 "<command-line>"$/ a # 31 "<command-line>"' \\
- -e 's/^# 1 "<command-line>" 2$/# 32 "<command-line>" 2/'
-fi
-exit 0
-EOF
- cat <<'EOF' >file.c
-int foo;
-EOF
- chmod +x buggy-cpp
- backdate buggy-cpp
- $CCACHE ./buggy-cpp -c file.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 0
- checkstat 'cache miss' 1
- $CCACHE ./buggy-cpp -DNOT_AFFECTING=1 -c file.c
- checkstat 'cache hit (direct)' 0
- checkstat 'cache hit (preprocessed)' 1
- checkstat 'cache miss' 1
+SUITE_input_charset_PROBE() {
+ touch test.c
+ if ! $UNCACHED_COMPILE -c -finput-charset=latin1 test.c >/dev/null 2>&1; then
+ echo "compiler doesn't support -finput-charset"
+ fi
}
-symlinks_suite() {
- ##################################################################
- testname="symlink to source directory"
-
- mkdir dir
- cd dir
- mkdir -p d1/d2
- echo '#define A "OK"' >d1/h.h
- cat <<EOF >d1/d2/c.c
-#include <stdio.h>
-#include "../h.h"
-int main() { printf("%s\n", A); }
-EOF
- echo '#define A "BUG"' >h.h
- ln -s d1/d2 d3
-
- CCACHE_BASEDIR=/ $CCACHE $COMPILER -c $PWD/d3/c.c
- $COMPILER -c $PWD/d3/c.c
- $COMPILER c.o -o c
- result=$(./c)
- if [ "$result" != OK ]; then
- test_failed "Incorrect header file used"
- fi
+SUITE_input_charset() {
+ # -------------------------------------------------------------------------
+ TEST "-finput-charset"
- cd ..
- rm -rf dir
+ printf '#include <wchar.h>\nwchar_t foo[] = L"\xbf";\n' >latin1.c
- ##################################################################
- testname="symlink to source file"
+ $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
- mkdir dir
- cd dir
- mkdir d
- echo '#define A "BUG"' >d/h.h
- cat <<EOF >d/c.c
-#include <stdio.h>
-#include "h.h"
-int main() { printf("%s\n", A); }
-EOF
- echo '#define A "OK"' >h.h
- ln -s d/c.c c.c
+ $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
- CCACHE_BASEDIR=/ $CCACHE $COMPILER -c $PWD/c.c
- $COMPILER c.o -o c
- result=$(./c)
- if [ "$result" != OK ]; then
- test_failed "Incorrect header file used"
- fi
+ CCACHE_NOCPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
- cd ..
- rm -rf dir
+ CCACHE_NOCPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
}
-######################################################################
+# =============================================================================
# main program
if pwd | grep '[^A-Za-z0-9/.,=_%+-]' >/dev/null 2>&1; then
exit 1
fi
-suites="$*"
if [ -n "$CC" ]; then
COMPILER="$CC"
else
CCACHE=`pwd`/ccache
fi
-# save the type of compiler because some test may not work on all compilers
-COMPILER_TYPE_CLANG=0
-COMPILER_TYPE_GCC=0
+COMPILER_TYPE_CLANG=false
+COMPILER_TYPE_GCC=false
-COMPILER_USES_LLVM=0
-HOST_OS_APPLE=0
+COMPILER_USES_LLVM=false
+COMPILER_USES_MINGW=false
+
+HOST_OS_APPLE=false
+HOST_OS_LINUX=false
+HOST_OS_WINDOWS=false
compiler_version="`$COMPILER --version 2>&1 | head -1`"
case $compiler_version in
*gcc*|*g++*|2.95*)
- COMPILER_TYPE_GCC=1
+ COMPILER_TYPE_GCC=true
;;
*clang*)
- COMPILER_TYPE_CLANG=1
+ COMPILER_TYPE_CLANG=true
;;
*)
echo "WARNING: Compiler $COMPILER not supported (version: $compiler_version) -- not running tests" >&2
case $compiler_version in
*llvm*|*LLVM*)
- COMPILER_USES_LLVM=1
+ COMPILER_USES_LLVM=true
+ ;;
+ *MINGW*|*mingw*)
+ COMPILER_USES_MINGW=true
;;
esac
-host_os="`uname -s`"
-case $host_os in
+case $(uname -s) in
+ *MINGW*|*mingw*)
+ HOST_OS_WINDOWS=true
+ ;;
*Darwin*)
- HOST_OS_APPLE=1
+ HOST_OS_APPLE=true
+ ;;
+ *Linux*)
+ HOST_OS_LINUX=true
;;
esac
-TESTDIR=testdir.$$
-rm -rf $TESTDIR
-mkdir $TESTDIR
-cd $TESTDIR || exit 1
-
-CCACHE_DIR=`pwd`/.ccache
-export CCACHE_DIR
-CCACHE_LOGFILE=`pwd`/ccache.log
-export CCACHE_LOGFILE
-CCACHE_CONFIGPATH=`pwd`/ccache.conf
-export CCACHE_CONFIGPATH
-touch $CCACHE_CONFIGPATH
-
+if $HOST_OS_WINDOWS; then
+ PATH_DELIM=";"
+else
+ PATH_DELIM=":"
+fi
-if [ $HOST_OS_APPLE -eq 1 ]; then
+if $HOST_OS_APPLE; then
# Grab the developer directory from the environment or try xcode-select
if [ "$XCODE_DEVELOPER_DIR" = "" ]; then
XCODE_DEVELOPER_DIR=`xcode-select --print-path`
# ---------------------------------------
+TESTDIR=testdir.$$
+ABS_TESTDIR=$PWD/$TESTDIR
+rm -rf $TESTDIR
+mkdir $TESTDIR
+cd $TESTDIR || exit 1
+
+# ---------------------------------------
+
all_suites="
base
-link !win32
+nocpp2
+multi_arch
+serialize_diagnostics
+debug_prefix_map
+masquerading
hardlink
-nlevels4
-nlevels1
-basedir !win32
direct
+basedir
compression
readonly
readonly_direct
-extrafiles
cleanup
pch
-symlinks
upgrade
-prefix
-buggy_cpp
+input_charset
"
-case $host_os in
- *MINGW*|*mingw*)
- export CCACHE_DETECT_SHEBANG
- CCACHE_DETECT_SHEBANG=1
- PATH_DELIM=";"
- all_suites="`echo "$all_suites" | grep -v '!win32'`"
- ;;
- *)
- PATH_DELIM=":"
- all_suites="`echo "$all_suites" | cut -d' ' -f1`"
- ;;
-esac
+compiler_location=$(which $COMPILER)
+if [ "$compiler_location" = "$COMPILER" ]; then
+ echo "Compiler: $COMPILER"
+else
+ echo "Compiler: $COMPILER ($(which $COMPILER))"
+fi
+echo "Compiler version: $($COMPILER --version | head -n 1)"
+echo
-echo compiler: `which $COMPILER`
-echo version: `$COMPILER --version`
-echo test dir: $TESTDIR
+VERBOSE=false
+[ "$1" = "-v" ] && { VERBOSE=true; shift; }
+suites="$*"
if [ -z "$suites" ]; then
suites="$all_suites"
fi
run_suite $suite
done
-# ---------------------------------------
-
-cd ..
-rm -rf $TESTDIR
-echo test done - OK
+cd /
+rm -rf $ABS_TESTDIR
+green PASSED
exit 0
-/*
- * Copyright (C) 2010-2014 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#include "ccache.h"
-#include "test/framework.h"
+#include "../ccache.h"
+#include "framework.h"
#include "util.h"
+#include <float.h>
+#include <math.h>
#if defined(HAVE_TERMIOS_H)
#define USE_COLOR
#include <termios.h>
static int verbose;
static const char COLOR_END[] = "\x1b[m";
-static const char COLOR_GREEN[] = "\x1b[32m";
-static const char COLOR_RED[] = "\x1b[31m";
+static const char COLOR_GREEN[] = "\x1b[1;32m";
+static const char COLOR_RED[] = "\x1b[1;31m";
#define COLOR(tty, color) ((tty) ? COLOR_ ## color : "")
suite_fn *suite;
int tty = is_tty(1);
- x_unsetenv("GCC_COLORS"); /* Avoid confusing argument processing tests. */
+ x_unsetenv("GCC_COLORS"); // Avoid confusing argument processing tests.
verbose = verbose_output;
for (suite = suites; *suite; suite++) {
while (true) {
test_index = (*suite)(test_index + 1);
if (test_index == 0) {
- /* We have reached the end of the suite. */
+ // We have reached the end of the suite.
break;
}
}
}
bool
+cct_check_float_eq(const char *file, int line, const char *expression,
+ double expected, double actual)
+{
+ if (fabs(expected - actual) < DBL_EPSILON) {
+ cct_check_passed(file, line, expression);
+ return true;
+ } else {
+ char *exp_str = format("%.1f", (double)expected);
+ char *act_str = format("%.1f", (double)actual);
+ cct_check_failed(file, line, expression, exp_str, act_str);
+ free(exp_str);
+ free(act_str);
+ return false;
+ }
+}
+bool
cct_check_int_eq(const char *file, int line, const char *expression,
int64_t expected, int64_t actual)
{
cct_check_passed(file, line, expression);
return true;
} else {
-#ifdef HAVE_LONG_LONG
+#if defined(HAVE_LONG_LONG) && !defined(__MINGW32__)
char *exp_str = format("%lld", (long long)expected);
char *act_str = format("%lld", (long long)actual);
#else
void
cct_wipe(const char *path)
{
- /* TODO: rewrite using traverse(). */
+ // TODO: rewrite using traverse().
+#ifndef __MINGW32__
char *command = format("rm -rf %s", path);
+#else
+ char *command = format("rd /s /q %s", path);
+#endif
if (system(command) != 0) {
perror(command);
}
-/*
- * Copyright (C) 2010-2012 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef TEST_FRAMEWORK_H
#define TEST_FRAMEWORK_H
-#include "ccache.h"
+#include "../ccache.h"
-/*****************************************************************************/
+// ============================================================================
#define TEST_SUITE(name) \
unsigned suite_##name(unsigned _start_point) \
unsigned _test_counter = 0; \
cct_suite_begin(#name); \
{ \
- /* Empty due to macro trickery. */
+ // Empty due to macro trickery.
#define TEST(name) \
cct_test_end(); \
return 0; /* We have reached the end. */ \
}
-/*****************************************************************************/
+// ============================================================================
#define CHECKM(assertion, message) \
do { \
} \
} while (false)
-/*****************************************************************************/
+// ============================================================================
#define CHECK_INT_EQ(expected, actual) \
do { \
} \
} while (false)
-/*****************************************************************************/
+// ============================================================================
+
+#define CHECK_FLOAT_EQ(expected, actual) \
+ do { \
+ if (!cct_check_float_eq(__FILE__, __LINE__, #actual, (expected), \
+ (actual))) { \
+ cct_test_end(); \
+ cct_suite_end(); \
+ return _test_counter; \
+ } \
+ } while (false)
+
+// ============================================================================
#define CHECK_STR_EQ(expected, actual) \
CHECK_POINTER_EQ_BASE(str, expected, actual, false, false)
#define CHECK_STR_EQ_FREE12(expected, actual) \
CHECK_POINTER_EQ_BASE(str, expected, actual, true, true)
-/*****************************************************************************/
+// ============================================================================
#define CHECK_ARGS_EQ(expected, actual) \
CHECK_POINTER_EQ_BASE(args, expected, actual, false, false)
#define CHECK_ARGS_EQ_FREE12(expected, actual) \
CHECK_POINTER_EQ_BASE(args, expected, actual, true, true)
-/*****************************************************************************/
+// ============================================================================
typedef unsigned (*suite_fn)(unsigned);
int cct_run(suite_fn *suites, int verbose);
void cct_check_passed(const char *file, int line, const char *assertion);
void cct_check_failed(const char *file, int line, const char *assertion,
const char *expected, const char *actual);
+bool cct_check_float_eq(const char *file, int line, const char *expression,
+ double expected, double actual);
bool cct_check_int_eq(const char *file, int line, const char *expression,
int64_t expected, int64_t actual);
bool cct_check_str_eq(const char *file, int line, const char *expression,
-/* Mode: -*-c-*- */
-/*
- * Copyright (C) 2010 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#include "test/framework.h"
+#include "framework.h"
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
-#include "getopt_long.h"
+#include "../getopt_long.h"
#endif
+// *INDENT-OFF* disable uncrustify
#define SUITE(name) unsigned suite_ ## name(unsigned);
-#include "test/suites.h"
+#include "suites.h"
#undef SUITE
+// *INDENT-ON* enable uncrustify
const char USAGE_TEXT[] =
"Usage:\n"
{
suite_fn suites[] = {
#define SUITE(name) &suite_ ## name,
-#include "test/suites.h"
+#include "suites.h"
#undef SUITE
NULL
};
-/*
- * Copyright (C) 2010, 2012 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * This file contains tests for the functions operating on struct args.
- */
-
-#include "ccache.h"
-#include "test/framework.h"
-#include "test/util.h"
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for the functions operating on struct args.
+
+#include "../ccache.h"
+#include "framework.h"
+#include "util.h"
TEST_SUITE(args)
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) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * This file contains tests for the processing of compiler arguments.
- */
-
-#include "ccache.h"
-#include "conf.h"
-#include "test/framework.h"
-#include "test/util.h"
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for the processing of compiler arguments.
+
+#include "../ccache.h"
+#include "../conf.h"
+#include "framework.h"
+#include "util.h"
extern struct conf *conf;
+static char *
+get_root(void)
+{
+#ifndef _WIN32
+ return x_strdup("/");
+#else
+ char volume[4]; // "C:\"
+ GetVolumePathName(get_cwd(), volume, sizeof(volume));
+ return x_strdup(volume);
+#endif
+}
+
+static char *
+get_posix_path(char *path)
+{
+#ifndef _WIN32
+ return x_strdup(path);
+#else
+ char *posix;
+ char *p;
+
+ // /-escape volume.
+ if (path[0] >= 'A' && path[0] <= 'Z' && path[1] == ':') {
+ posix = format("/%s", path);
+ } else {
+ posix = x_strdup(path);
+ }
+ // Convert slashes.
+ for (p = posix; *p; p++) {
+ if (*p == '\\') {
+ *p = '/';
+ }
+ }
+ return posix;
+#endif
+}
+
TEST_SUITE(argument_processing)
TEST(dash_E_should_result_in_called_for_preprocessing)
{
#define CMD \
"cc -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2" \
- " -Wp,-MD,wpmd -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf"
+ " -Wp,-MD,wpmd -Wp,-MMD,wpmmd"
struct args *orig = args_init_from_string(CMD " -c foo.c -o foo.o");
struct args *exp_cpp = args_init_from_string(CMD);
#undef CMD
args_free(orig);
}
-TEST(preprocessor_only_flags_should_only_be_sent_to_the_preprocessor)
+TEST(cpp_only_flags_to_preprocessor_if_run_second_cpp_is_false)
{
#define CMD \
"cc -I. -idirafter . -iframework. -imacros . -imultilib ." \
" -include test.h -include-pch test.pch -iprefix . -iquote ." \
" -isysroot . -isystem . -iwithprefix . -iwithprefixbefore ." \
" -DTEST_MACRO -DTEST_MACRO2=1 -F. -trigraphs -fworking-directory" \
- " -fno-working-directory -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2" \
- " -MQ mq1 -MQ mq2 -Wp,-MD,wpmd -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt" \
- " -Wp,-MQ,wpmq -Wp,-MF,wpf"
+ " -fno-working-directory -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 " \
+ " -MQ mq1 -MQ mq2 -Wp,-MD,wpmd -Wp,-MMD,wpmmd"
struct args *orig = args_init_from_string(CMD " -c foo.c -o foo.o");
struct args *exp_cpp = args_init_from_string(CMD);
#undef CMD
struct args *act_cpp = NULL, *act_cc = NULL;
create_file("foo.c", "");
+ conf->run_second_cpp = false;
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(cpp_only_flags_to_preprocessor_and_compiler_if_run_second_cpp_is_true)
+{
+#define CMD \
+ "cc -I. -idirafter . -iframework. -imacros . -imultilib ." \
+ " -include test.h -include-pch test.pch -iprefix . -iquote ." \
+ " -isysroot . -isystem . -iwithprefix . -iwithprefixbefore ." \
+ " -DTEST_MACRO -DTEST_MACRO2=1 -F. -trigraphs -fworking-directory" \
+ " -fno-working-directory"
+#define DEP_OPTS \
+ " -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 " \
+ " -MQ mq1 -MQ mq2 -Wp,-MD,wpmd -Wp,-MMD,wpmmd"
+ struct args *orig = args_init_from_string(CMD DEP_OPTS " -c foo.c -o foo.o");
+ struct args *exp_cpp = args_init_from_string(CMD DEP_OPTS);
+ struct args *exp_cc = args_init_from_string(CMD " -c");
+#undef CMD
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ conf->run_second_cpp = true;
CHECK(cc_process_args(orig, &act_cpp, &act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
create_file("foo.c", "");
free(conf->base_dir);
- conf->base_dir = x_strdup("/");
+ conf->base_dir = get_root();
current_working_dir = get_cwd();
arg_string = format("cc --sysroot=%s/foo -c foo.c", current_working_dir);
orig = args_init_from_string(arg_string);
+ free(arg_string);
CHECK(cc_process_args(orig, &act_cpp, &act_cc));
CHECK_STR_EQ(act_cpp->argv[1], "--sysroot=./foo");
struct args *exp_cpp = args_init_from_string("gcc");
struct args *exp_cc = args_init_from_string("gcc");
struct args *act_cpp = NULL, *act_cc = NULL;
- char *s;
+ char *s, *path;
create_file("foo.c", "");
mkdir("some", 0777);
mkdir("some/dir", 0777);
- s = format("-fprofile-generate=%s", x_realpath("some/dir"));
+ path = x_realpath("some/dir");
+ s = format("-fprofile-generate=%s", path);
+ free(path);
args_add(exp_cpp, s);
args_add(exp_cc, s);
args_add(exp_cc, "-c");
args_free(orig);
}
+TEST(isystem_flag_with_separate_arg_should_be_rewritten_if_basedir_is_used)
+{
+ extern char *current_working_dir;
+ char *arg_string;
+ struct args *orig;
+ struct args *act_cpp = NULL, *act_cc = NULL;
+
+ create_file("foo.c", "");
+ free(conf->base_dir);
+ conf->base_dir = get_root();
+ current_working_dir = get_cwd();
+ arg_string = format("cc -isystem %s/foo -c foo.c", current_working_dir);
+ orig = args_init_from_string(arg_string);
+ free(arg_string);
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_STR_EQ("./foo", act_cpp->argv[2]);
+
+ args_free(orig);
+ args_free(act_cpp);
+ args_free(act_cc);
+}
+
+TEST(isystem_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used)
+{
+ extern char *current_working_dir;
+ char *cwd;
+ char *arg_string;
+ struct args *orig;
+ struct args *act_cpp = NULL, *act_cc = NULL;
+
+ create_file("foo.c", "");
+ free(conf->base_dir);
+ conf->base_dir = x_strdup("/"); // posix
+ current_working_dir = get_cwd();
+ // Windows path doesn't work concatenated.
+ cwd = get_posix_path(current_working_dir);
+ arg_string = format("cc -isystem%s/foo -c foo.c", cwd);
+ orig = args_init_from_string(arg_string);
+ free(arg_string);
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_STR_EQ("-isystem./foo", act_cpp->argv[1]);
+
+ free(cwd);
+ args_free(orig);
+ args_free(act_cpp);
+ args_free(act_cc);
+}
+
+TEST(I_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used)
+{
+ extern char *current_working_dir;
+ char *cwd;
+ char *arg_string;
+ struct args *orig;
+ struct args *act_cpp = NULL, *act_cc = NULL;
+
+ create_file("foo.c", "");
+ free(conf->base_dir);
+ conf->base_dir = x_strdup("/"); // posix
+ current_working_dir = get_cwd();
+ // Windows path doesn't work concatenated.
+ cwd = get_posix_path(current_working_dir);
+ arg_string = format("cc -I%s/foo -c foo.c", cwd);
+ orig = args_init_from_string(arg_string);
+ free(arg_string);
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_STR_EQ("-I./foo", act_cpp->argv[1]);
+
+ free(cwd);
+ args_free(orig);
+ args_free(act_cpp);
+ args_free(act_cc);
+}
+
TEST_SUITE_END
-/*
- * Copyright (C) 2010, 2012 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * This file contains tests for the compopt_* functions.
- */
-
-#include "ccache.h"
-#include "compopt.h"
-#include "test/framework.h"
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for the compopt_* functions.
+
+#include "../ccache.h"
+#include "../compopt.h"
+#include "framework.h"
TEST_SUITE(compopt)
-/*
- * Copyright (C) 2011-2014 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "conf.h"
-#include "test/framework.h"
-#include "test/util.h"
-
-#define N_CONFIG_ITEMS 27
+// Copyright (C) 2011-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "../conf.h"
+#include "framework.h"
+#include "util.h"
+
+#define N_CONFIG_ITEMS 31
static struct {
char *descr;
const char *origin;
CHECK(!conf->disable);
CHECK_STR_EQ("", conf->extra_files_to_hash);
CHECK(!conf->hard_link);
- CHECK(!conf->hash_dir);
+ CHECK(conf->hash_dir);
+ CHECK_STR_EQ("", conf->ignore_headers_in_manifest);
+ CHECK(!conf->keep_comments_cpp);
+ CHECK_FLOAT_EQ(0.8f, conf->limit_multiple);
CHECK_STR_EQ("", conf->log_file);
CHECK_INT_EQ(0, conf->max_files);
CHECK_INT_EQ((uint64_t)5 * 1000 * 1000 * 1000, conf->max_size);
CHECK_STR_EQ("", conf->path);
CHECK_STR_EQ("", conf->prefix_command);
+ CHECK_STR_EQ("", conf->prefix_command_cpp);
CHECK(!conf->read_only);
CHECK(!conf->read_only_direct);
CHECK(!conf->recache);
- CHECK(!conf->run_second_cpp);
+ CHECK(conf->run_second_cpp);
CHECK_INT_EQ(0, conf->sloppiness);
CHECK(conf->stats);
CHECK_STR_EQ("", conf->temporary_dir);
CHECK_STR_EQ("rabbit", user);
create_file(
"ccache.conf",
+#ifndef _WIN32
"base_dir = /$USER/foo/${USER} \n"
+#else
+ "base_dir = C:/$USER/foo/${USER}\n"
+#endif
"cache_dir=\n"
"cache_dir = $USER$/${USER}/.ccache\n"
"\n"
"disable = true\n"
"extra_files_to_hash = a:b c:$USER\n"
"hard_link = true\n"
- "hash_dir = true\n"
+ "hash_dir = false\n"
+ "ignore_headers_in_manifest = a:b/c\n"
+ "keep_comments_cpp = true\n"
+ "limit_multiple = 1.0\n"
"log_file = $USER${USER} \n"
"max_files = 17\n"
"max_size = 123M\n"
"path = $USER.x\n"
"prefix_command = x$USER\n"
+ "prefix_command_cpp = y\n"
"read_only = true\n"
"read_only_direct = true\n"
"recache = true\n"
- "run_second_cpp = true\n"
- "sloppiness = file_macro ,time_macros, include_file_mtime,include_file_ctime,file_stat_matches, pch_defines \n"
+ "run_second_cpp = false\n"
+ "sloppiness = file_macro ,time_macros, include_file_mtime,include_file_ctime,file_stat_matches,pch_defines , no_system_headers \n"
"stats = false\n"
"temporary_dir = ${USER}_foo\n"
"umask = 777\n"
- "unify = true"); /* Note: no newline */
+ "unify = true"); // Note: no newline.
CHECK(conf_read(conf, "ccache.conf", &errmsg));
CHECK(!errmsg);
+#ifndef _WIN32
CHECK_STR_EQ_FREE1(format("/%s/foo/%s", user, user), conf->base_dir);
+#else
+ CHECK_STR_EQ_FREE1(format("C:/%s/foo/%s", user, user), conf->base_dir);
+#endif
CHECK_STR_EQ_FREE1(format("%s$/%s/.ccache", user, user), conf->cache_dir);
CHECK_INT_EQ(4, conf->cache_dir_levels);
CHECK_STR_EQ("foo", conf->compiler);
CHECK(conf->disable);
CHECK_STR_EQ_FREE1(format("a:b c:%s", user), conf->extra_files_to_hash);
CHECK(conf->hard_link);
- CHECK(conf->hash_dir);
+ CHECK(!conf->hash_dir);
+ CHECK_STR_EQ("a:b/c", conf->ignore_headers_in_manifest);
+ CHECK(conf->keep_comments_cpp);
+ CHECK_FLOAT_EQ(1.0, conf->limit_multiple);
CHECK_STR_EQ_FREE1(format("%s%s", user, user), conf->log_file);
CHECK_INT_EQ(17, conf->max_files);
CHECK_INT_EQ(123 * 1000 * 1000, conf->max_size);
CHECK_STR_EQ_FREE1(format("%s.x", user), conf->path);
CHECK_STR_EQ_FREE1(format("x%s", user), conf->prefix_command);
+ CHECK_STR_EQ("y", conf->prefix_command_cpp);
CHECK(conf->read_only);
CHECK(conf->read_only_direct);
CHECK(conf->recache);
- CHECK(conf->run_second_cpp);
+ CHECK(!conf->run_second_cpp);
CHECK_INT_EQ(SLOPPY_INCLUDE_FILE_MTIME|SLOPPY_INCLUDE_FILE_CTIME|
SLOPPY_FILE_MACRO|SLOPPY_TIME_MACROS|
- SLOPPY_FILE_STAT_MATCHES|SLOPPY_PCH_DEFINES,
+ SLOPPY_FILE_STAT_MATCHES|SLOPPY_NO_SYSTEM_HEADERS|
+ SLOPPY_PCH_DEFINES,
conf->sloppiness);
CHECK(!conf->stats);
CHECK_STR_EQ_FREE1(format("%s_foo", user), conf->temporary_dir);
CHECK(!conf_read(conf, "ccache.conf", &errmsg));
CHECK_STR_EQ_FREE2("ccache.conf:1: syntax error: missing '}' after \"foo\"",
errmsg);
- /* Other cases tested in test_util.c. */
+ // Other cases tested in test_util.c.
conf_free(conf);
}
CHECK(!conf_read(conf, "ccache.conf", &errmsg));
CHECK_STR_EQ_FREE2("ccache.conf:1: invalid size: \"foo\"",
errmsg);
- /* Other cases tested in test_util.c. */
+ // Other cases tested in test_util.c.
conf_free(conf);
}
true,
"efth",
true,
+ .hash_dir = false,
+ "ihim",
true,
+ 0.0,
"lf",
4711,
98.7 * 1000 * 1000,
"p",
"pc",
+ "pcc",
true,
true,
true,
- true,
+ .run_second_cpp = false,
SLOPPY_FILE_MACRO|SLOPPY_INCLUDE_FILE_MTIME|
SLOPPY_INCLUDE_FILE_CTIME|SLOPPY_TIME_MACROS|
- SLOPPY_FILE_STAT_MATCHES|SLOPPY_PCH_DEFINES,
+ SLOPPY_FILE_STAT_MATCHES|SLOPPY_PCH_DEFINES|
+ SLOPPY_NO_SYSTEM_HEADERS,
false,
"td",
022,
conf.item_origins = x_malloc(N_CONFIG_ITEMS * sizeof(char *));
for (i = 0; i < N_CONFIG_ITEMS; ++i) {
+#ifndef __MINGW32__
conf.item_origins[i] = format("origin%zu", i);
+#else
+ conf.item_origins[i] = format("origin%u", (unsigned) i);
+#endif
}
conf_print_items(&conf, conf_item_receiver, NULL);
CHECK_STR_EQ("disable = true", received_conf_items[n++].descr);
CHECK_STR_EQ("extra_files_to_hash = efth", received_conf_items[n++].descr);
CHECK_STR_EQ("hard_link = true", received_conf_items[n++].descr);
- CHECK_STR_EQ("hash_dir = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("hash_dir = false", received_conf_items[n++].descr);
+ CHECK_STR_EQ("ignore_headers_in_manifest = ihim",
+ received_conf_items[n++].descr);
+ CHECK_STR_EQ("keep_comments_cpp = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("limit_multiple = 0.0", received_conf_items[n++].descr);
CHECK_STR_EQ("log_file = lf", received_conf_items[n++].descr);
CHECK_STR_EQ("max_files = 4711", received_conf_items[n++].descr);
CHECK_STR_EQ("max_size = 98.7M", received_conf_items[n++].descr);
CHECK_STR_EQ("path = p", received_conf_items[n++].descr);
CHECK_STR_EQ("prefix_command = pc", received_conf_items[n++].descr);
+ CHECK_STR_EQ("prefix_command_cpp = pcc", received_conf_items[n++].descr);
CHECK_STR_EQ("read_only = true", received_conf_items[n++].descr);
CHECK_STR_EQ("read_only_direct = true", received_conf_items[n++].descr);
CHECK_STR_EQ("recache = true", received_conf_items[n++].descr);
- CHECK_STR_EQ("run_second_cpp = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("run_second_cpp = false", received_conf_items[n++].descr);
CHECK_STR_EQ("sloppiness = file_macro, include_file_mtime,"
" include_file_ctime, time_macros, pch_defines,"
- " file_stat_matches",
+ " file_stat_matches, no_system_headers",
received_conf_items[n++].descr);
CHECK_STR_EQ("stats = false", received_conf_items[n++].descr);
CHECK_STR_EQ("temporary_dir = td", received_conf_items[n++].descr);
CHECK_STR_EQ("unify = true", received_conf_items[n++].descr);
for (i = 0; i < N_CONFIG_ITEMS; ++i) {
+#ifndef __MINGW32__
char *expected = format("origin%zu", i);
- CHECK_STR_EQ(expected, received_conf_items[i].origin);
+#else
+ char *expected = format("origin%u", (unsigned) i);
+#endif
+ CHECK_STR_EQ_FREE1(expected, received_conf_items[i].origin);
}
free_received_conf_items();
-/*
- * Copyright (C) 2010-2011 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "ccache.h"
-#include "counters.h"
-#include "test/framework.h"
-#include "test/util.h"
+// Copyright (C) 2010-2011 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "../ccache.h"
+#include "../counters.h"
+#include "framework.h"
+#include "util.h"
TEST_SUITE(counters)
-/*
- * Copyright (C) 2010 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * This file contains tests for functions in hash.c.
- */
-
-#include "ccache.h"
-#include "test/framework.h"
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for functions in hash.c.
+
+#include "../ccache.h"
+#include "framework.h"
TEST_SUITE(hash)
-/*
- * Copyright (C) 2010, 2012 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * This file contains tests for functions in hashutil.c.
- */
-
-#include "ccache.h"
-#include "hashutil.h"
-#include "test/framework.h"
-#include "test/util.h"
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for functions in hashutil.c.
+
+#include "../ccache.h"
+#include "../hashutil.h"
+#include "framework.h"
+#include "util.h"
TEST_SUITE(hashutil)
struct mdfour h1, h2;
hash_start(&h1);
hash_start(&h2);
+#ifndef _WIN32
create_file("stderr.sh", "#!/bin/sh\necho foo >&2\n");
chmod("stderr.sh", 0555);
CHECK(hash_command_output(&h1, "echo foo", "not used"));
CHECK(hash_command_output(&h2, "./stderr.sh", "not used"));
+#else
+ create_file("stderr.bat", "@echo off\r\necho foo>&2\r\n");
+ CHECK(hash_command_output(&h1, "echo foo", "not used"));
+ CHECK(hash_command_output(&h2, "stderr.bat", "not used"));
+#endif
CHECK(hash_equal(&h1, &h2));
}
struct mdfour h1, h2;
hash_start(&h1);
hash_start(&h2);
+#ifndef _WIN32
create_file("foo.sh", "#!/bin/sh\necho foo\necho bar\n");
chmod("foo.sh", 0555);
CHECK(hash_multicommand_output(&h2, "echo foo; echo bar", "not used"));
CHECK(hash_multicommand_output(&h1, "./foo.sh", "not used"));
+#else
+ create_file("foo.bat", "@echo off\r\necho foo\r\necho bar\r\n");
+ CHECK(hash_multicommand_output(&h2, "echo foo; echo bar", "not used"));
+ CHECK(hash_multicommand_output(&h1, "foo.bat", "not used"));
+#endif
CHECK(hash_equal(&h1, &h2));
}
-/*
- * Copyright (C) 2010 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-/*
- * This file contains tests for functions in lockfile.c.
- */
+// This file contains tests for functions in lockfile.c.
-#include "ccache.h"
-#include "test/framework.h"
-#include "test/util.h"
+#include "../ccache.h"
+#include "framework.h"
+#include "util.h"
TEST_SUITE(lockfile)
-/*
- * Copyright (C) 2010-2011 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * This file contains tests for statistics handling.
- */
-
-#include "ccache.h"
-#include "counters.h"
-#include "test/framework.h"
-#include "test/util.h"
+// Copyright (C) 2010-2011 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for statistics handling.
+
+#include "../ccache.h"
+#include "../counters.h"
+#include "framework.h"
+#include "util.h"
TEST_SUITE(stats)
-/*
- * 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
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * This file contains tests for functions in util.c.
- */
-
-#include "ccache.h"
-#include "test/framework.h"
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for functions in util.c.
+
+#include "../ccache.h"
+#include "framework.h"
TEST_SUITE(util)
size_t i;
struct { const char *size; int64_t expected; } sizes[] = {
{"0", 0},
- {"42", (int64_t)42 * 1000 * 1000 * 1000}, /* Default suffix: G */
+ {"42", (int64_t)42 * 1000 * 1000 * 1000}, // Default suffix: G
{"78k", 78 * 1000},
{"78K", 78 * 1000},
-/*
- * Copyright (C) 2010 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2010-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#include "system.h"
-#include "test/util.h"
+#include "../system.h"
+#include "util.h"
#ifdef _WIN32
# define lstat(a, b) stat(a, b)
return lstat(path, &st) == 0;
}
-bool
-is_symlink(const char *path)
-{
-#ifdef _WIN32
- (void) path;
- return 0;
-#else
- struct stat st;
- return lstat(path, &st) == 0 && S_ISLNK(st.st_mode);
-#endif
-}
-
void
create_file(const char *path, const char *content)
{
#ifndef TEST_UTIL_H
#define TEST_UTIL_H
+#include <stdbool.h>
+
bool path_exists(const char *path);
bool is_symlink(const char *path);
void create_file(const char *path, const char *content);
-/*
- * Copyright (C) 2002 Andrew Tridgell
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * C/C++ unifier
- *
- * The idea is that changes that don't affect the resulting C code should not
- * change the hash. This is achieved by folding white-space and other
- * non-semantic fluff in the input into a single unified format.
- *
- * This unifier was design to match the output of the unifier in compilercache,
- * which is flex based. The major difference is that this unifier is much
- * faster (about 2x) and more forgiving of syntactic errors. Continuing on
- * syntactic errors is important to cope with C/C++ extensions in the local
- * compiler (for example, inline assembly systems).
- */
+// Copyright (C) 2002 Andrew Tridgell
+// Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// C/C++ unifier
+//
+// The idea is that changes that don't affect the resulting C code should not
+// change the hash. This is achieved by folding white-space and other
+// non-semantic fluff in the input into a single unified format.
+//
+// This unifier was design to match the output of the unifier in compilercache,
+// which is flex based. The major difference is that this unifier is much
+// faster (about 2x) and more forgiving of syntactic errors. Continuing on
+// syntactic errors is important to cope with C/C++ extensions in the local
+// compiler (for example, inline assembly systems).
#include "ccache.h"
const char *toks[7];
} tokens[256];
-/* build up the table used by the unifier */
+// Build up the table used by the unifier.
static void
build_table(void)
{
- unsigned char c;
- int i;
static bool done;
-
if (done) {
return;
}
done = true;
memset(tokens, 0, sizeof(tokens));
- for (c = 0; c < 128; c++) {
+ for (unsigned char c = 0; c < 128; c++) {
if (isalpha(c) || c == '_') {
tokens[c].type |= C_ALPHA;
}
tokens['-'].type |= C_SIGN;
tokens['+'].type |= C_SIGN;
- for (i = 0; s_tokens[i]; i++) {
- c = s_tokens[i][0];
+ for (int i = 0; s_tokens[i]; i++) {
+ unsigned char c = s_tokens[i][0];
tokens[c].type |= C_TOKEN;
tokens[c].toks[tokens[c].num_toks] = s_tokens[i];
tokens[c].num_toks++;
}
}
-/* buffer up characters before hashing them */
+// Buffer up characters before hashing them.
static void
pushchar(struct mdfour *hash, unsigned char c)
{
}
}
-/* hash some C/C++ code after unifying */
+// Hash some C/C++ code after unifying.
static void
unify(struct mdfour *hash, unsigned char *p, size_t size)
{
- size_t ofs;
- unsigned char q;
- int i;
-
build_table();
- for (ofs = 0; ofs < size; ) {
+ for (size_t ofs = 0; ofs < size; ) {
if (p[ofs] == '#') {
if ((size-ofs) > 2 && p[ofs+1] == ' ' && isdigit(p[ofs+2])) {
do {
}
if (tokens[p[ofs]].type & C_QUOTE) {
- q = p[ofs];
+ unsigned char q = p[ofs];
pushchar(hash, p[ofs]);
do {
ofs++;
}
if (tokens[p[ofs]].type & C_TOKEN) {
- q = p[ofs];
+ unsigned char q = p[ofs];
+ int i;
for (i = 0; i < tokens[q].num_toks; i++) {
unsigned char *s = (unsigned char *)tokens[q].toks[i];
int len = strlen((char *)s);
}
-/* hash a file that consists of preprocessor output, but remove any line
- number information from the hash
- */
+// Hash a file that consists of preprocessor output, but remove any line number
+// information from the hash.
int
unify_hash(struct mdfour *hash, const char *fname)
{
char *data;
size_t size;
-
if (!read_file(fname, 0, &data, &size)) {
stats_update(STATS_PREPROCESSOR);
return -1;
-/*
- * Copyright (C) 2002 Andrew Tridgell
- * Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// Copyright (C) 2002 Andrew Tridgell
+// Copyright (C) 2009-2016 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 Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
#ifdef _WIN32
#include <windows.h>
#include <sys/locking.h>
+#include <psapi.h>
+#include <tchar.h>
#endif
static FILE *logfile;
return MAXPATHLEN;
#elif defined(_PC_PATH_MAX)
long maxlen = pathconf(path, _PC_PATH_MAX);
- if (maxlen >= 4096) {
- return maxlen;
- } else {
- return 4096;
- }
+ return maxlen >= 4096 ? maxlen : 4096;
#endif
}
-/*
- * Warn about failure writing to the log file and then exit.
- */
+// 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. */
+ // 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));
x_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);
- rc1 = vfprintf(logfile, format, ap);
- rc2 = fprintf(logfile, "\n");
+ int rc1 = vfprintf(logfile, format, ap);
+ int rc2 = fprintf(logfile, "\n");
if (rc1 < 0 || rc2 < 0) {
warn_log_fail();
}
}
-/*
- * Write a message to the log file (adding a newline) and flush.
- */
+// Write a message to the log file (adding a newline) and flush.
void
cc_log(const char *format, ...)
{
}
}
-/*
- * Write a message to the log file (adding a newline) without flushing and with
- * a reused timestamp.
- */
+// Write a message to the log file (adding a newline) without flushing and with
+// a reused timestamp.
void
cc_bulklog(const char *format, ...)
{
va_end(ap);
}
-/*
- * Log an executed command to the CCACHE_LOGFILE location.
- */
+// Log an executed command to the CCACHE_LOGFILE location.
void
cc_log_argv(const char *prefix, char **argv)
{
- int rc;
if (!init_log()) {
return;
}
log_prefix(true);
fputs(prefix, logfile);
print_command(logfile, argv);
- rc = fflush(logfile);
+ int rc = fflush(logfile);
if (rc) {
warn_log_fail();
}
}
-/* something went badly wrong! */
+// Something went badly wrong!
void
fatal(const char *format, ...)
{
va_list ap;
- char msg[1000];
-
va_start(ap, format);
+ char msg[1000];
vsnprintf(msg, sizeof(msg), format, ap);
va_end(ap);
x_exit(1);
}
-/*
- * Copy all data from fd_in to fd_out, decompressing data from fd_in if needed.
- */
+// Copy all data from fd_in to fd_out, decompressing data from fd_in if needed.
void
copy_fd(int fd_in, int fd_out)
{
- char buf[10240];
- int n;
- gzFile gz_in;
-
- gz_in = gzdopen(dup(fd_in), "rb");
-
+ gzFile gz_in = gzdopen(dup(fd_in), "rb");
if (!gz_in) {
fatal("Failed to copy fd");
}
+ int n;
+ char buf[READ_BUFFER_SIZE];
while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) {
ssize_t written = 0;
do {
}
#ifndef HAVE_MKSTEMP
-/* cheap and nasty mkstemp replacement */
+// Cheap and nasty mkstemp replacement.
int
mkstemp(char *template)
{
}
#endif
-/*
- * Copy src to dest, decompressing src if needed. compress_level > 0 decides
- * whether dest will be compressed, and with which compression level. Returns 0
- * on success and -1 on failure. On failure, errno represents the error.
- */
+// Copy src to dest, decompressing src if needed. compress_level > 0 decides
+// 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)
{
- int fd_in, fd_out;
- gzFile gz_in = NULL, gz_out = NULL;
- char buf[10240];
- int n, written;
- char *tmp_name;
- struct stat st;
- int errnum;
+ int fd_out;
+ gzFile gz_in = NULL;
+ gzFile gz_out = NULL;
int saved_errno = 0;
- /* open destination file */
- tmp_name = x_strdup(dest);
+ // Open destination file.
+ char *tmp_name = x_strdup(dest);
fd_out = create_tmp_fd(&tmp_name);
cc_log("Copying %s to %s via %s (%scompressed)",
src, dest, tmp_name, compress_level > 0 ? "" : "un");
- /* open source file */
- fd_in = open(src, O_RDONLY | O_BINARY);
+ // Open source file.
+ int fd_in = open(src, O_RDONLY | O_BINARY);
if (fd_in == -1) {
saved_errno = errno;
cc_log("open error: %s", strerror(saved_errno));
}
if (compress_level > 0) {
- /*
- * A gzip file occupies at least 20 bytes, so it will always
- * occupy an entire filesystem block, even for empty files.
- * Turn off compression for empty files to save some space.
- */
+ // A gzip file occupies at least 20 bytes, so it will always occupy an
+ // entire filesystem block, even for empty files. Turn off compression for
+ // empty files to save some space.
+ struct stat st;
if (x_fstat(fd_in, &st) != 0) {
goto error;
}
gzsetparams(gz_out, compress_level, Z_DEFAULT_STRATEGY);
}
+ int n;
+ char buf[READ_BUFFER_SIZE];
while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) {
+ int written;
if (compress_level > 0) {
written = gzwrite(gz_out, buf, n);
} else {
}
if (written != n) {
if (compress_level > 0) {
+ int errnum;
cc_log("gzwrite error: %s (errno: %s)",
gzerror(gz_in, &errnum),
strerror(saved_errno));
}
}
- /*
- * gzeof won't tell if there's an error in the trailing CRC, so we must check
- * gzerror before considering everything OK.
- */
+ // gzeof won't tell if there's an error in the trailing CRC, so we must check
+ // gzerror before considering everything OK.
+ int errnum;
gzerror(gz_in, &errnum);
if (!gzeof(gz_in) || (errnum != Z_OK && errnum != Z_STREAM_END)) {
saved_errno = errno;
fchmod(fd_out, 0666 & ~get_umask());
#endif
- /* the close can fail on NFS if out of space */
+ // The close can fail on NFS if out of space.
if (close(fd_out) == -1) {
saved_errno = errno;
cc_log("close error: %s", strerror(saved_errno));
return -1;
}
-/* Run copy_file() and, if successful, delete the source file. */
+// Run copy_file() and, if successful, delete the source file.
int
move_file(const char *src, const char *dest, int compress_level)
{
- int ret;
-
- ret = copy_file(src, dest, compress_level);
+ int ret = copy_file(src, dest, compress_level);
if (ret != -1) {
x_unlink(src);
}
return ret;
}
-/*
- * Like move_file(), but assumes that src is uncompressed and that src and dest
- * are on the same file system.
- */
+// Like move_file(), but assumes that src is uncompressed and that src and dest
+// are on the same file system.
int
move_uncompressed_file(const char *src, const char *dest, int compress_level)
{
}
}
-/* test if a file is zlib compressed */
+// Test if a file is zlib compressed.
bool
file_is_compressed(const char *filename)
{
- FILE *f;
-
- f = fopen(filename, "rb");
+ FILE *f = fopen(filename, "rb");
if (!f) {
return false;
}
- /* test if file starts with 1F8B, which is zlib's
- * magic number */
+ // Test if file starts with 1F8B, which is zlib's magic number.
if ((fgetc(f) != 0x1f) || (fgetc(f) != 0x8b)) {
fclose(f);
return false;
return true;
}
-/* make sure a directory exists */
+// Make sure a directory exists.
int
create_dir(const char *dir)
{
return 0;
}
-/* Create directories leading to path. Returns 0 on success, otherwise -1. */
+// Create directories leading to path. Returns 0 on success, otherwise -1.
int
create_parent_dirs(const char *path)
{
- struct stat st;
int res;
char *parent = dirname(path);
-
+ struct stat st;
if (stat(parent, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
res = 0;
res = create_parent_dirs(parent);
if (res == 0) {
res = mkdir(parent, 0777);
- /* Have to handle the condition of the directory already existing because
- * the file system could have changed in between calling stat and
- * actually creating the directory. This can happen when there are
- * multiple instances of ccache running and trying to create the same
- * directory chain, which usually is the case when the cache root does
- * not initially exist. As long as one of the processes creates the
- * directories then our condition is satisfied and we avoid a race
- * condition.
- */
+ // Have to handle the condition of the directory already existing because
+ // the file system could have changed in between calling stat and
+ // actually creating the directory. This can happen when there are
+ // multiple instances of ccache running and trying to create the same
+ // directory chain, which usually is the case when the cache root does
+ // not initially exist. As long as one of the processes creates the
+ // directories then our condition is satisfied and we avoid a race
+ // condition.
if (res != 0 && errno == EEXIST) {
res = 0;
}
return res;
}
-/*
- * Return a static string with the current hostname.
- */
+// Return a static string with the current hostname.
const char *
get_hostname(void)
{
return hostname;
}
- WORD wVersionRequested;
- WSADATA wsaData;
- int err;
-
- wVersionRequested = MAKEWORD(2, 2);
-
- err = WSAStartup(wVersionRequested, &wsaData);
+ WORD w_version_requested = MAKEWORD(2, 2);
+ WSADATA wsa_data;
+ int err = WSAStartup(w_version_requested, &wsa_data);
if (err != 0) {
- /* Tell the user that we could not find a usable Winsock DLL. */
+ // 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. */
+ if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.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;
+ LPVOID lp_msg_buf;
+ DWORD dw = WSAGetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &lpMsgBuf, 0, NULL);
+ (LPTSTR) &lp_msg_buf, 0, NULL);
- lpDisplayBuf = (LPVOID) LocalAlloc(
+ LPVOID lp_display_buf = (LPVOID) LocalAlloc(
LMEM_ZEROINIT,
- (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) __FILE__) + 200)
+ (lstrlen((LPCTSTR) lp_msg_buf) + lstrlen((LPCTSTR) __FILE__) + 200)
* sizeof(TCHAR));
- _snprintf((LPTSTR) lpDisplayBuf,
- LocalSize(lpDisplayBuf) / sizeof(TCHAR),
+ _snprintf((LPTSTR) lp_display_buf,
+ LocalSize(lp_display_buf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"), __FILE__, dw,
- lpMsgBuf);
+ lp_msg_buf);
- cc_log("can't get hostname OS returned error: %s", (char *)lpDisplayBuf);
+ cc_log("can't get hostname OS returned error: %s", (char *)lp_display_buf);
- LocalFree(lpMsgBuf);
- LocalFree(lpDisplayBuf);
+ LocalFree(lp_msg_buf);
+ LocalFree(lp_display_buf);
}
WSACleanup();
#endif
return hostname;
}
-/*
- * Return a string to be passed to mkstemp to create a temporary file. Also
- * tries to cope with NFS by adding the local hostname.
- */
+// Return a string to be passed to mkstemp to create a temporary file. Also
+// tries to cope with NFS by adding the local hostname.
const char *
tmp_string(void)
{
static char *ret;
-
if (!ret) {
ret = format("%s.%u.XXXXXX", get_hostname(), (unsigned)getpid());
}
-
return ret;
}
-/*
- * Return the hash result as a hex string. Size -1 means don't include size
- * suffix. Caller frees.
- */
+// Return the hash result as a hex string. Size -1 means don't include size
+// suffix. Caller frees.
char *
format_hash_as_string(const unsigned char *hash, int size)
{
- char *ret;
int i;
-
- ret = x_malloc(53);
+ char *ret = x_malloc(53);
for (i = 0; i < 16; i++) {
sprintf(&ret[i*2], "%02x", (unsigned) hash[i]);
}
if (size >= 0) {
sprintf(&ret[i*2], "-%d", size);
}
-
return ret;
}
"Signature: 8a477f597d28d172789f06886806bc55\n"
"# This file is a cache directory tag created by ccache.\n"
"# For information about cache directory tags, see:\n"
- "# http://www.brynosaurus.com/cachedir/\n";
+ "#\thttp://www.brynosaurus.com/cachedir/\n";
int
create_cachedirtag(const char *dir)
{
- struct stat st;
- FILE *f;
char *filename = format("%s/CACHEDIR.TAG", dir);
+ struct stat st;
if (stat(filename, &st) == 0) {
if (S_ISREG(st.st_mode)) {
goto success;
errno = EEXIST;
goto error;
}
- f = fopen(filename, "w");
+ FILE *f = fopen(filename, "w");
if (!f) {
goto error;
}
return 1;
}
-/* Construct a string according to a format. Caller frees. */
+// Construct a string according to a format. Caller frees.
char *
format(const char *format, ...)
{
va_list ap;
- char *ptr = NULL;
-
va_start(ap, format);
+
+ char *ptr = NULL;
if (vasprintf(&ptr, format, ap) == -1) {
fatal("Out of memory in format");
}
return ptr;
}
-/* This is like strdup() but dies if the malloc fails. */
+// This is like strdup() but dies if the malloc fails.
char *
x_strdup(const char *s)
{
- char *ret;
- ret = strdup(s);
+ char *ret = strdup(s);
if (!ret) {
fatal("Out of memory in x_strdup");
}
return ret;
}
-/* This is like strndup() but dies if the malloc fails. */
+// This is like strndup() but dies if the malloc fails.
char *
x_strndup(const char *s, size_t n)
{
- char *ret;
#ifndef HAVE_STRNDUP
- size_t m;
-
- if (!s)
+ if (!s) {
return NULL;
- m = 0;
+ }
+ size_t m = 0;
while (m < n && s[m]) {
m++;
}
- ret = malloc(m + 1);
+ char *ret = malloc(m + 1);
if (ret) {
memcpy(ret, s, m);
ret[m] = '\0';
}
#else
- ret = strndup(s, n);
+ char *ret = strndup(s, n);
#endif
if (!ret) {
fatal("x_strndup: Could not allocate %lu bytes", (unsigned long)n);
return ret;
}
-/* This is like malloc() but dies if the malloc fails. */
+// This is like malloc() but dies if the malloc fails.
void *
x_malloc(size_t size)
{
- void *ret;
if (size == 0) {
- /*
- * malloc() may return NULL if size is zero, so always do this to make sure
- * that the code handles it regardless of platform.
- */
+ // malloc() may return NULL if size is zero, so always do this to make sure
+ // that the code handles it regardless of platform.
return NULL;
}
- ret = malloc(size);
+ void *ret = malloc(size);
if (!ret) {
fatal("x_malloc: Could not allocate %lu bytes", (unsigned long)size);
}
return ret;
}
-/* This is like calloc() but dies if the allocation fails. */
+// This is like calloc() but dies if the allocation fails.
void *
x_calloc(size_t nmemb, size_t size)
{
- void *ret;
if (nmemb * size == 0) {
- /*
- * calloc() may return NULL if nmemb or size is 0, so always do this to
- * make sure that the code handles it regardless of platform.
- */
+ // calloc() may return NULL if nmemb or size is 0, so always do this to
+ // make sure that the code handles it regardless of platform.
return NULL;
}
- ret = calloc(nmemb, size);
+ void *ret = calloc(nmemb, size);
if (!ret) {
fatal("x_calloc: Could not allocate %lu bytes", (unsigned long)size);
}
return ret;
}
-/* This is like realloc() but dies if the malloc fails. */
+// This is like realloc() but dies if the malloc fails.
void *
x_realloc(void *ptr, size_t size)
{
- void *p2;
if (!ptr) {
return x_malloc(size);
}
- p2 = realloc(ptr, size);
+ void *p2 = realloc(ptr, size);
if (!p2) {
fatal("x_realloc: Could not allocate %lu bytes", (unsigned long)size);
}
return p2;
}
-/* This is like unsetenv. */
+// This is like unsetenv.
void x_unsetenv(const char *name)
{
#ifdef HAVE_UNSETENV
unsetenv(name);
#else
- putenv(x_strdup(name)); /* Leak to environment. */
+ putenv(x_strdup(name)); // Leak to environment.
#endif
}
-/* Like fstat() but also call cc_log on failure. */
+// Like fstat() but also call cc_log on failure.
int
x_fstat(int fd, struct stat *buf)
{
return result;
}
-/* Like lstat() but also call cc_log on failure. */
+// Like lstat() but also call cc_log on failure.
int
x_lstat(const char *pathname, struct stat *buf)
{
return result;
}
-/* Like stat() but also call cc_log on failure. */
+// Like stat() but also call cc_log on failure.
int
x_stat(const char *pathname, struct stat *buf)
{
return result;
}
-/*
- * Construct a string according to the format and store it in *ptr. The
- * original *ptr is then freed.
- */
+// Construct a string according to the format and store it in *ptr. The
+// original *ptr is then freed.
void
reformat(char **ptr, const char *format, ...)
{
char *saved = *ptr;
- va_list ap;
-
*ptr = NULL;
+
+ va_list ap;
va_start(ap, format);
if (vasprintf(ptr, format, ap) == -1) {
fatal("Out of memory in reformat");
}
}
-/*
- * Recursive directory traversal. fn() is called on all entries in the tree.
- */
+// Recursive directory traversal. fn() is called on all entries in the tree.
void
traverse(const char *dir, void (*fn)(const char *, struct stat *))
{
- DIR *d;
- struct dirent *de;
-
- d = opendir(dir);
+ DIR *d = opendir(dir);
if (!d) {
return;
}
+ struct dirent *de;
while ((de = readdir(d))) {
- char *fname;
- struct stat st;
-
if (str_eq(de->d_name, ".")) {
continue;
}
continue;
}
- fname = format("%s/%s", dir, de->d_name);
+ char *fname = format("%s/%s", dir, de->d_name);
+ struct stat st;
if (lstat(fname, &st)) {
if (errno != ENOENT && errno != ESTALE) {
fatal("lstat %s failed: %s", fname, strerror(errno));
}
-/* return the base name of a file - caller frees */
+// Return the base name of a file - caller frees.
char *
basename(const char *path)
{
- char *p;
- p = strrchr(path, '/');
+ char *p = strrchr(path, '/');
if (p) {
path = p + 1;
}
return x_strdup(path);
}
-/* return the dir name of a file - caller frees */
+// Return the dir name of a file - caller frees.
char *
dirname(const char *path)
{
- char *p;
+ char *s = x_strdup(path);
+ char *p = strrchr(s, '/');
#ifdef _WIN32
- char *p2;
-#endif
- char *s;
- s = x_strdup(path);
- p = strrchr(s, '/');
-#ifdef _WIN32
- p2 = strrchr(s, '\\');
+ char *p2 = strrchr(s, '\\');
if (!p || (p2 && p < p2)) {
p = p2;
}
return s;
}
-/*
- * Return the file extension (including the dot) of a path as a pointer into
- * path. If path has no file extension, the empty string and the end of path is
- * returned.
- */
+// Return the file extension (including the dot) of a path as a pointer into
+// path. If path has no file extension, the empty string and the end of path is
+// returned.
const char *
get_extension(const char *path)
{
size_t len = strlen(path);
- const char *p;
-
- for (p = &path[len - 1]; p >= path; --p) {
+ for (const char *p = &path[len - 1]; p >= path; --p) {
if (*p == '.') {
return p;
}
return &path[len];
}
-/*
- * Return a string containing the given path without the filename extension.
- * Caller frees.
- */
+// Return a string containing the given path without the filename extension.
+// Caller frees.
char *
remove_extension(const char *path)
{
return x_strndup(path, strlen(path) - strlen(get_extension(path)));
}
-/* return size on disk of a file */
+// Return size on disk of a file.
size_t
file_size(struct stat *st)
{
#else
size_t size = st->st_blocks * 512;
if ((size_t)st->st_size > size) {
- /* probably a broken stat() call ... */
+ // Probably a broken stat() call...
size = (st->st_size + 1023) & ~1023;
}
return size;
#endif
}
-/* Format a size as a human-readable string. Caller frees. */
+// Format a size as a human-readable string. Caller frees.
char *
format_human_readable_size(uint64_t v)
{
return s;
}
-/* Format a size as a parsable string. Caller frees. */
+// Format a size as a parsable string. Caller frees.
char *
format_parsable_size_with_suffix(uint64_t size)
{
return s;
}
-/*
- * Parse a "size value", i.e. a string that can end in k, M, G, T (10-based
- * suffixes) or Ki, Mi, Gi, Ti (2-based suffixes). For backward compatibility,
- * K is also recognized as a synonym of k.
- */
+// Parse a "size value", i.e. a string that can end in k, M, G, T (10-based
+// suffixes) or Ki, Mi, Gi, Ti (2-based suffixes). For backward compatibility,
+// K is also recognized as a synonym of k.
bool
parse_size_with_suffix(const char *str, uint64_t *size)
{
- char *p;
- double x;
-
errno = 0;
- x = strtod(str, &p);
+
+ char *p;
+ double x = strtod(str, &p);
if (errno != 0 || x < 0 || p == str || *str == '\0') {
return false;
}
}
if (*p != '\0') {
- unsigned multiplier;
- if (*(p+1) == 'i') {
- multiplier = 1024;
- } else {
- multiplier = 1000;
- }
+ unsigned multiplier = *(p+1) == 'i' ? 1024 : 1000;
switch (*p) {
case 'T':
x *= multiplier;
return false;
}
} else {
- /* Default suffix: G. */
+ // Default suffix: G.
x *= 1000 * 1000 * 1000;
}
*size = x;
}
-/* A sane realpath() function, trying to cope with stupid path limits and a
- * broken API. */
+#if !defined(HAVE_REALPATH) && \
+ defined(_WIN32) && \
+ !defined(HAVE_GETFINALPATHNAMEBYHANDLEW)
+static BOOL GetFileNameFromHandle(HANDLE file_handle, TCHAR *filename,
+ WORD cch_filename)
+{
+ BOOL success = FALSE;
+
+ // Get the file size.
+ DWORD file_size_hi = 0;
+ DWORD file_size_lo = GetFileSize(file_handle, &file_size_hi);
+ if (file_size_lo == 0 && file_size_hi == 0) {
+ // Cannot map a file with a length of zero.
+ return FALSE;
+ }
+
+ // Create a file mapping object.
+ HANDLE file_map =
+ CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 1, NULL);
+ if (!file_map) {
+ return FALSE;
+ }
+
+ // Create a file mapping to get the file name.
+ void *mem = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 1);
+ if (mem) {
+ if (GetMappedFileName(GetCurrentProcess(),
+ mem,
+ filename,
+ cch_filename)) {
+ // Translate path with device name to drive letters.
+ TCHAR temp[512];
+ temp[0] = '\0';
+
+ if (GetLogicalDriveStrings(512-1, temp)) {
+ TCHAR name[MAX_PATH];
+ TCHAR drive[3] = TEXT(" :");
+ BOOL found = FALSE;
+ TCHAR *p = temp;
+
+ do {
+ // Copy the drive letter to the template string.
+ *drive = *p;
+
+ // Look up each device name.
+ if (QueryDosDevice(drive, name, MAX_PATH)) {
+ size_t name_len = _tcslen(name);
+ if (name_len < MAX_PATH) {
+ found = _tcsnicmp(filename, name, name_len) == 0
+ && *(filename + name_len) == _T('\\');
+ if (found) {
+ // Reconstruct filename using temp_file and replace device path
+ // with DOS path.
+ TCHAR temp_file[MAX_PATH];
+ _sntprintf(temp_file,
+ MAX_PATH - 1,
+ TEXT("%s%s"),
+ drive,
+ filename+name_len);
+ _tcsncpy(filename, temp_file, _tcslen(temp_file));
+ }
+ }
+ }
+
+ // Go to the next NULL character.
+ while (*p++) {
+ // Do nothing.
+ }
+ } while (!found && *p); // End of string.
+ }
+ }
+ success = TRUE;
+ UnmapViewOfFile(mem);
+ }
+
+ CloseHandle(file_map);
+ return success;
+}
+#endif
+
+// A sane realpath() function, trying to cope with stupid path limits and a
+// broken API. Caller frees.
char *
x_realpath(const char *path)
{
long maxlen = path_max(path);
- char *ret, *p;
-#if !defined(HAVE_REALPATH) && defined(_WIN32)
- HANDLE path_handle;
-#endif
-
- ret = x_malloc(maxlen);
+ char *ret = x_malloc(maxlen);
+ char *p;
#if HAVE_REALPATH
p = realpath(path, ret);
#elif defined(_WIN32)
- path_handle = CreateFile(
+ if (path[0] == '/') {
+ path++; // Skip leading slash.
+ }
+ HANDLE path_handle = CreateFile(
path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != path_handle) {
+#ifdef HAVE_GETFINALPATHNAMEBYHANDLEW
GetFinalPathNameByHandle(path_handle, ret, maxlen, FILE_NAME_NORMALIZED);
+#else
+ GetFileNameFromHandle(path_handle, ret, maxlen);
+#endif
CloseHandle(path_handle);
- p = ret + 4; /* strip \\?\ from the file name */
+ 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 */
+ // Yes, there are such systems. This replacement relies on the fact that when
+ // we call x_realpath we only care about symlinks.
{
int len = readlink(path, ret, maxlen-1);
if (len == -1) {
return NULL;
}
-/* a getcwd that will returns an allocated buffer */
+// A getcwd that will returns an allocated buffer.
char *
gnu_getcwd(void)
{
}
#ifndef HAVE_STRTOK_R
-/* strtok_r replacement */
+// strtok_r replacement.
char *
strtok_r(char *str, const char *delim, char **saveptr)
{
- int len;
- char *ret;
- if (!str)
+ if (!str) {
str = *saveptr;
- len = strlen(str);
- ret = strtok(str, delim);
+ }
+ int len = strlen(str);
+ char *ret = strtok(str, delim);
if (ret) {
char *save = ret;
- while (*save++) ;
- if ((len + 1) == (intptr_t) (save - str))
+ while (*save++) {
+ // Do nothing.
+ }
+ if ((len + 1) == (intptr_t) (save - str)) {
save--;
+ }
*saveptr = save;
}
return ret;
}
#endif
-/*
- * Create an empty temporary file. *fname will be reallocated and set to the
- * resulting filename. Returns an open file descriptor to the file.
- */
+// Create an empty temporary file. *fname will be reallocated and set to the
+// resulting filename. Returns an open file descriptor to the file.
int
create_tmp_fd(char **fname)
{
return fd;
}
-/*
- * Create an empty temporary file. *fname will be reallocated and set to the
- * resulting filename. Returns an open FILE*.
- */
+// Create an empty temporary file. *fname will be reallocated and set to the
+// resulting filename. Returns an open FILE*.
FILE *
create_tmp_file(char **fname, const char *mode)
{
return file;
}
-/*
- * Return current user's home directory, or NULL if it can't be determined.
- */
+// Return current user's home directory, or NULL if it can't be determined.
const char *
get_home_directory(void)
{
return NULL;
}
-/*
- * Get the current directory by reading $PWD. If $PWD isn't sane, gnu_getcwd()
- * is used. Caller frees.
- */
+// Get the current directory by reading $PWD. If $PWD isn't sane, gnu_getcwd()
+// is used. Caller frees.
char *
get_cwd(void)
{
- char *pwd;
- char *cwd;
struct stat st_pwd;
struct stat st_cwd;
- cwd = gnu_getcwd();
+ char *cwd = gnu_getcwd();
if (!cwd) {
return NULL;
}
- pwd = getenv("PWD");
+ char *pwd = getenv("PWD");
if (!pwd) {
return cwd;
}
}
}
-/*
- * Check whether s1 and s2 have the same executable name.
- */
+// Check whether s1 and s2 have the same executable name.
bool
same_executable_name(const char *s1, const char *s2)
{
#endif
}
-/*
- * Compute the length of the longest directory path that is common to two
- * paths. s1 is assumed to be the path to a directory.
- */
+// Compute the length of the longest directory path that is common to two
+// paths. s1 is assumed to be the path to a directory.
size_t
common_dir_prefix_length(const char *s1, const char *s2)
{
p2--;
}
if (!*p1 && !*p2 && p2 == s2 + 1) {
- /* Special case for s1 and s2 both being "/". */
+ // Special case for s1 and s2 both being "/".
return 0;
}
return p1 - s1;
}
-/*
- * Compute a relative path from from (an absolute path to a directory) to to (a
- * path). Assumes that both from and to are well-formed and canonical. Caller
- * frees.
- */
+// Compute a relative path from from (an absolute path to a directory) to to (a
+// path). Assumes that both from and to are well-formed and canonical. Caller
+// frees.
char *
get_relative_path(const char *from, const char *to)
{
size_t common_prefix_len;
- int i;
char *result;
assert(from && is_absolute_path(from));
}
#ifdef _WIN32
- // Both paths are absolute, drop the drive letters
- assert(from[0] == to[0]); // Assume the same drive letter
+ // Paths can be escaped by a slash for use with -isystem.
+ if (from[0] == '/') {
+ from++;
+ }
+ if (to[0] == '/') {
+ to++;
+ }
+ // Both paths are absolute, drop the drive letters.
+ assert(from[0] == to[0]); // Assume the same drive letter.
from += 2;
to += 2;
#endif
if (strlen(to) > common_prefix_len) {
reformat(&result, "%s%s", result, to + common_prefix_len + 1);
}
- i = strlen(result) - 1;
- while (i >= 0 && result[i] == '/') {
+ for (int i = strlen(result) - 1; i >= 0 && result[i] == '/'; i--) {
result[i] = '\0';
- i--;
}
if (str_eq(result, "")) {
free(result);
return result;
}
-/*
- * Return whether path is absolute.
- */
+// Return whether path is absolute.
bool
is_absolute_path(const char *path)
{
#endif
}
-/*
- * Return whether the argument is a full path.
- */
+// Return whether the argument is a full path.
bool
is_full_path(const char *path)
{
- if (strchr(path, '/'))
+ if (strchr(path, '/')) {
return true;
+ }
#ifdef _WIN32
- if (strchr(path, '\\'))
+ if (strchr(path, '\\')) {
return true;
+ }
#endif
return false;
}
-/*
- * Update the modification time of a file in the cache to save it from LRU
- * cleanup.
- */
+bool is_symlink(const char *path)
+{
+#ifdef _WIN32
+ (void)path;
+ return false;
+#else
+ struct stat st;
+ return x_lstat(path, &st) == 0 && ((st.st_mode & S_IFMT) == S_IFLNK);
+#endif
+}
+
+// Update the modification time of a file in the cache to save it from LRU
+// cleanup.
void
update_mtime(const char *path)
{
#endif
}
-/*
- * If exit() already has been called, call _exit(), otherwise exit(). This is
- * used to avoid calling exit() inside an atexit handler.
- */
+// If exit() already has been called, call _exit(), otherwise exit(). This is
+// used to avoid calling exit() inside an atexit handler.
void
x_exit(int status)
{
}
}
-/*
- * Rename oldpath to newpath (deleting newpath).
- */
+// Rename oldpath to newpath (deleting newpath).
int
x_rename(const char *oldpath, const char *newpath)
{
#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. */
+ // 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;
+ LPVOID lp_msg_buf;
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);
+ NULL, dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lp_msg_buf,
+ 0,
+ NULL);
- lpDisplayBuf = (LPVOID) LocalAlloc(
+ LPVOID lp_display_buf = (LPVOID) LocalAlloc(
LMEM_ZEROINIT,
- (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) __FILE__) + 40)
+ (lstrlen((LPCTSTR) lp_msg_buf) + lstrlen((LPCTSTR) __FILE__) + 40)
* sizeof(TCHAR));
- _snprintf((LPTSTR) lpDisplayBuf,
- LocalSize(lpDisplayBuf) / sizeof(TCHAR),
- TEXT("%s failed with error %d: %s"), __FILE__, dw, lpMsgBuf);
+ _snprintf((LPTSTR) lp_display_buf,
+ LocalSize(lp_display_buf) / sizeof(TCHAR),
+ TEXT("%s failed with error %d: %s"), __FILE__, dw, lp_msg_buf);
cc_log("can't rename file %s to %s OS returned error: %s",
- oldpath, newpath, (char *) lpDisplayBuf);
+ oldpath, newpath, (char *) lp_display_buf);
- LocalFree(lpMsgBuf);
- LocalFree(lpDisplayBuf);
+ LocalFree(lp_msg_buf);
+ LocalFree(lp_display_buf);
return -1;
} else {
return 0;
#endif
}
-/*
- * Remove path, NFS hazardous. Use only for temporary files that will not exist
- * on other systems. That is, the path should include tmp_string().
- */
+// Remove path, NFS hazardous. Use only for temporary files that will not exist
+// on other systems. That is, the path should include tmp_string().
int
tmp_unlink(const char *path)
{
- int rc;
cc_log("Unlink %s", path);
- rc = unlink(path);
+ int rc = unlink(path);
if (rc) {
cc_log("Unlink failed: %s", strerror(errno));
}
return rc;
}
-/*
- * Remove path, NFS safe.
- */
+// Remove path, NFS safe.
int
x_unlink(const char *path)
{
- /*
- * If path is on an NFS share, unlink isn't atomic, so we rename to a temp
- * file. We don't care if the temp file is trashed, so it's always safe to
- * unlink it first.
- */
- char *tmp_name = format("%s.rm.%s", path, tmp_string());
- int result = 0;
int saved_errno = 0;
+
+ // If path is on an NFS share, unlink isn't atomic, so we rename to a temp
+ // file. We don't care if the temp file is trashed, so it's always safe to
+ // unlink it first.
+ char *tmp_name = format("%s.rm.%s", path, tmp_string());
cc_log("Unlink %s via %s", path, tmp_name);
+
+ int result = 0;
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 it was released in a race, that's OK.
if (errno != ENOENT && errno != ESTALE) {
result = -1;
saved_errno = errno;
}
}
+
out:
free(tmp_name);
if (result) {
}
#ifndef _WIN32
-/* Like readlink() but returns the string or NULL on failure. Caller frees. */
+// Like readlink() but returns the string or NULL on failure. Caller frees.
char *
x_readlink(const char *path)
{
long maxlen = path_max(path);
- ssize_t len;
- char *buf;
-
- buf = x_malloc(maxlen);
- len = readlink(path, buf, maxlen-1);
+ char *buf = x_malloc(maxlen);
+ ssize_t len = readlink(path, buf, maxlen-1);
if (len == -1) {
free(buf);
return NULL;
}
#endif
-/*
- * Reads the content of a file. Size hint 0 means no hint. Returns true on
- * success, otherwise false.
- */
+// Reads the content of a file. Size hint 0 means no hint. Returns true on
+// success, otherwise false.
bool
read_file(const char *path, size_t size_hint, char **data, size_t *size)
{
- int fd, ret;
- size_t pos = 0, allocated;
-
if (size_hint == 0) {
struct stat st;
if (x_stat(path, &st) == 0) {
}
size_hint = (size_hint < 1024) ? 1024 : size_hint;
- fd = open(path, O_RDONLY | O_BINARY);
+ int fd = open(path, O_RDONLY | O_BINARY);
if (fd == -1) {
return false;
}
- allocated = size_hint;
+ size_t allocated = size_hint;
*data = x_malloc(allocated);
+ int ret;
+ size_t pos = 0;
while (true) {
if (pos > allocated / 2) {
allocated *= 2;
return true;
}
-/*
- * Return the content (with NUL termination) of a text file, or NULL on error.
- * Caller frees. Size hint 0 means no hint.
- */
+// Return the content (with NUL termination) of a text file, or NULL on error.
+// Caller frees. Size hint 0 means no hint.
char *
read_text_file(const char *path, size_t size_hint)
{
size_t size;
char *data;
-
if (read_file(path, size_hint, &data, &size)) {
data = x_realloc(data, size + 1);
data[size] = '\0';
static bool
expand_variable(const char **str, char **result, char **errmsg)
{
- bool curly;
- const char *p, *q;
- char *name;
- const char *value;
-
assert(**str == '$');
- p = *str + 1;
+
+ bool curly;
+ const char *p = *str + 1;
if (*p == '{') {
curly = true;
++p;
} else {
curly = false;
}
- q = p;
+
+ const char *q = p;
while (isalnum(*q) || *q == '_') {
++q;
}
}
if (q == p) {
- /* Special case: don't consider a single $ the start of a variable. */
+ // Special case: don't consider a single $ the start of a variable.
reformat(result, "%s$", *result);
return true;
}
- name = x_strndup(p, q - p);
- value = getenv(name);
+ char *name = x_strndup(p, q - p);
+ const char *value = getenv(name);
if (!value) {
*errmsg = format("environment variable \"%s\" not set", name);
free(name);
return true;
}
-/*
- * Substitute all instances of $VAR or ${VAR}, where VAR is an environment
- * variable, in a string. Caller frees. If one of the environment variables
- * doesn't exist, NULL will be returned and *errmsg will be an appropriate
- * error message (caller frees).
- */
+// Substitute all instances of $VAR or ${VAR}, where VAR is an environment
+// variable, in a string. Caller frees. If one of the environment variables
+// doesn't exist, NULL will be returned and *errmsg will be an appropriate
+// error message (caller frees).
char *
subst_env_in_string(const char *str, char **errmsg)
{
- const char *p; /* Interval start. */
- const char *q; /* Interval end. */
- char *result;
-
assert(errmsg);
*errmsg = NULL;
- result = x_strdup("");
- p = str;
- q = str;
+ char *result = x_strdup("");
+ const char *p = str; // Interval start.
+ const char *q = str; // Interval end.
for (q = str; *q; ++q) {
if (*q == '$') {
reformat(&result, "%s%.*s", result, (int)(q - p), p);
-const char CCACHE_VERSION[] = "3.2.9";
+const char CCACHE_VERSION[] = "3.3";
{
struct inflate_state FAR *state;
- if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16;
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return (long)(((unsigned long)0 - 1) << 16);
state = (struct inflate_state FAR *)strm->state;
- return ((long)(state->back) << 16) +
+ return (long)(((unsigned long)((long)state->back)) << 16) +
(state->mode == COPY ? state->length :
(state->mode == MATCH ? state->was - state->length : 0));
}