How to Use CCache with CMake?

77.2k views Asked by At

I would like to do the following: If CCache is present in PATH, use "ccache g++" for compilation, else use g++. I tried writing a small my-cmake script containing

    CC="ccache gcc" CXX="ccache g++" cmake $*

but it does not seem to work (running make still does not use ccache; I checked this using CMAKE_VERBOSE_MAKEFILE on).

Update:

As per this link I tried changing my script to

     cmake -D CMAKE_CXX_COMPILER="ccache" -D CMAKE_CXX_COMPILER_ARG1="g++" -D CMAKE_C_COMPILER="ccache" -D CMAKE_C_COMPILER_ARG1="gcc" $*

but cmake bails out complaining that a test failed on using the compiler ccache (which can be expected).

10

There are 10 answers

3
Nicolás On BEST ANSWER

I personally have /usr/lib/ccache in my $PATH. This directory contains loads of symlinks for every possible name the compiler could be called from (like gcc and gcc-4.3), all pointing to ccache.

And I didn't even create the symlinks. That directory comes pre-filled when I install ccache on Debian.

0
Nadir SOUALEM On

In my opinion the best way is to symlink gcc,g++ to ccache, but if you would like to use within cmake, try this:

export CC="ccache gcc" CXX="ccache g++" cmake ...
0
amit kumar On

I verified the following works (source: this link):

        CC="gcc" CXX="g++" cmake -D CMAKE_CXX_COMPILER="ccache" -D CMAKE_CXX_COMPILER_ARG1="g++" -D CMAKE_C_COMPILER="ccache" -D CMAKE_C_COMPILER_ARG1="gcc" $*

Update: I later realized that even this does not work. Strangely it works every alternate time (the other times cmake complains).

6
Babcool On

It is now possible to specify ccache as a launcher for compile commands and link commands (since cmake 2.8.0). That works for Makefile and Ninja generator. To do this, just set the following properties :

find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
endif()

It is also possible to set these properties only for specific directories or targets.

For Ninja, this is possible since version 3.4. For XCode, Craig Scott gives a workaround in his answer.

It's possible to use ccache for linking too:

    set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) 

However, @Emilio Cobos recommends against this as ccache doesn't improve linking speed and can mess with other types of cache like sccache.

Edit : Thanks to uprego and Lekensteyn's comment, I edited the answer to check if ccache is available before using it as launcher and for which generators is it possible to use a compile launcher.

9
Jacob On

As of CMake 3.4 you can do:

-DCMAKE_CXX_COMPILER_LAUNCHER=ccache

ref: https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_LAUNCHER.html

As of CMake 3.17 you can also use the env variable:

export CMAKE_CXX_COMPILER_LAUNCHER=ccache
cmake -S ... -B ...

ref: https://cmake.org/cmake/help/latest/envvar/CMAKE_LANG_COMPILER_LAUNCHER.html

1
Jürgen Weigert On

Let me add one important item that was not mentioned here before.

While bootstrapping a minimalistic build system from the ubuntu:18.04 docker image, I've found that order of installation makes a difference.

In my case ccache worked fine when calling gcc, but failed to catch invocations of the same compiler by the other names: cc and c++. To fully install ccache, you need to make sure all compilers are installed first, or add a call to update-ccache symlinks to be safe.

sudo /usr/sbin/update-ccache-symlinks
export PATH="/usr/lib/ccache/:$PATH"```

... and then (due to updated symlinks) also calls to cc and c++ get caught!
3
Craig Scott On

From CMake 3.1, it is possible to use ccache with the Xcode generator and Ninja is supported from CMake 3.4 onwards. Ninja will honour RULE_LAUNCH_COMPILE just like the Unix Makefiles generator (so @Babcool's answer gets you there for Ninja too), but getting ccache working for the Xcode generator takes a little more work. The following article explains the method in detail, focussing on a general implementation which works for all three CMake generators and making no assumptions about setting up ccache symlinks or the underlying compiler used (it still lets CMake decide the compiler):

https://crascit.com/2016/04/09/using-ccache-with-cmake/

The general gist of the article is as follows. The start of your CMakeLists.txt file should be set up something like this:

cmake_minimum_required(VERSION 2.8)

find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
    # Support Unix Makefiles and Ninja
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
endif()

project(SomeProject)

get_property(RULE_LAUNCH_COMPILE GLOBAL PROPERTY RULE_LAUNCH_COMPILE)
if(RULE_LAUNCH_COMPILE AND CMAKE_GENERATOR STREQUAL "Xcode")
    # Set up wrapper scripts
    configure_file(launch-c.in   launch-c)
    configure_file(launch-cxx.in launch-cxx)
    execute_process(COMMAND chmod a+rx
                            "${CMAKE_BINARY_DIR}/launch-c"
                            "${CMAKE_BINARY_DIR}/launch-cxx")

    # Set Xcode project attributes to route compilation through our scripts
    set(CMAKE_XCODE_ATTRIBUTE_CC         "${CMAKE_BINARY_DIR}/launch-c")
    set(CMAKE_XCODE_ATTRIBUTE_CXX        "${CMAKE_BINARY_DIR}/launch-cxx")
    set(CMAKE_XCODE_ATTRIBUTE_LD         "${CMAKE_BINARY_DIR}/launch-c")
    set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_BINARY_DIR}/launch-cxx")
endif()

The two script template files launch-c.in and launch-cxx.in look like this (they should be in the same directory as the CMakeLists.txt file):

launch-c.in:

#!/bin/sh
export CCACHE_CPP2=true
exec "${RULE_LAUNCH_COMPILE}" "${CMAKE_C_COMPILER}" "$@"

launch-cxx.in:

#!/bin/sh
export CCACHE_CPP2=true
exec "${RULE_LAUNCH_COMPILE}" "${CMAKE_CXX_COMPILER}" "$@"

The above uses RULE_LAUNCH_COMPILE alone for Unix Makefiles and Ninja, but for the Xcode generator it relies on help from CMake's CMAKE_XCODE_ATTRIBUTE_... variables support. The setting of the CC and CXX user-defined Xcode attributes to control the compiler command and LD and LDPLUSPLUS for the linker command is not, as far as I can tell, a documented feature of Xcode projects, but it does seem to work. If anyone can confirm it is officially supported by Apple, I'll update the linked article and this answer accordingly.

0
jpr42 On

Here are 2 methods I think are clean/robust, and also don't pollute your CMake code.

1.) Set environment variables

This method is nice since you don't have to individually set it up for each CMake project. The con is you may not want ccache for each CMake project.

# Requires CMake 3.17 (https://cmake.org/cmake/help/latest/envvar/CMAKE_LANG_COMPILER_LAUNCHER.html)
export CMAKE_CXX_COMPILER_LAUNCHER=/usr/bin/ccache
export CMAKE_C_COMPILER_LAUNCHER=/usr/bin/ccache

2.) Pass in cache variables during project configuration

Con a bit annoying to do for each project. This can be negated by your IDE though.

# Requires CMake 3.4
$ cmake ... -D CMAKE_CXX_COMPILER_LAUNCHER=/usr/bin/ccache \
  -D CMAKE_C_COMPILER_LAUNCHER=/usr/bin/ccache

NOTE: It isn't really necessary to specify the full path.

If ccache is in your path you can just specify ccache instead.

export CMAKE_CXX_COMPILER_LAUNCHER=ccache
export CMAKE_C_COMPILER_LAUNCHER=ccache

EDIT:

Note. Sometimes your CMake project will consume non-CMake projects. In that case you may need configure your PATH as suggested in Nicolás answer in order to cache everything.

0
ephemerr On

It is extending @Nicolas answer.

Add following line to your cmake file:

list(PREPEND CMAKE_PROGRAM_PATH /usr/lib/ccache)

Or add it as argument to cmake configuration step:

cmake -DCMAKE_PROGRAM_PATH=/usr/lib/ccache
0
jonas On

I didn't like to set a symlink from g++ to ccache. And CXX="ccache g++" didn't work for me as some cmake test case wanted to have just the compiler program without attributes.

So I used a small bash script instead:

#!/bin/bash
ccache g++ "$@"

and saved it as an executable in /usr/bin/ccache-g++.

Then C configured cmake to use /usr/bin/ccache-g++ as C++ compiler. This way it passes the cmake test cases and I feel more comfortable than having symlinks that I might forget about in 2 or 3 weeks and then maybe wonder if something doesn't work...