Using ccache with CMake
find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) message(STATUS "Set up ccache ...") #set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") endif()
对于 ExternalProject_Add 需要增加以下参数
CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER}"
CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER}"
对于使用 CMAKE_GENERATOR Ninja 选项可以配置ExternalProject使用Ninja来构建,
ExternalProject_Add(xxxxx PREFIX xxxxx SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/xxxxx" BUILD_ALWAYS 1 CMAKE_GENERATOR Ninja CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" CMAKE_ARGS "${CMAKE_ARGS};-DBUILD_GCC_64=${BUILD_GCC_64}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS_64}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS_64}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER}" )
或者在包含ExternalProject的top文件中配置: set(CMAKE_GENERATOR Ninja),top文件下所有ExternalProject都会使用Nina来构建
find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) message(STATUS "Set up ccache ...") #set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") endif() set(CMAKE_GENERATOR Ninja)
ExternalProject_Add(xxxxx PREFIX xxxxx SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/xxxxx" BUILD_ALWAYS 1 CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" CMAKE_ARGS "${CMAKE_ARGS};-DBUILD_GCC_64=${BUILD_GCC_64}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS_64}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS_64}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER}" CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER}" )
ExternalProject_Add(jsoncpp-project PREFIX "${prefix}" DOWNLOAD_DIR "${CMAKE_SOURCE_DIR}/deps/downloads" DOWNLOAD_NAME jsoncpp-1.9.2.tar.gz URL https://github.com/open-source-parsers/jsoncpp/archive/1.9.2.tar.gz URL_HASH SHA256=77a402fb577b2e0e5d0bdc1cf9c65278915cdb25171e3452c68b6da8a561f8f0 CMAKE_COMMAND ${JSONCPP_CMAKE_COMMAND} CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_INSTALL_LIBDIR=lib # Build static lib but suitable to be included in a shared lib. -DCMAKE_POSITION_INDEPENDENT_CODE=${BUILD_SHARED_LIBS} -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_PKGCONFIG_SUPPORT=OFF -DCMAKE_CXX_FLAGS=${JSONCPP_CXX_FLAGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} ${byproducts} )
https://stackoverflow.com/questions/1815688/how-to-use-ccache-with-cmake
As of CMAKE 3.4 you can do:
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
https://cloud.tencent.com/developer/ask/sof/112423
https://stacktuts.com/how-to-use-ccache-with-cmake-in-c
set(CMAKE_CXX_COMPILER_LAUNCHER ccache)
set(CMAKE_C_COMPILER_LAUNCHER ccache)
从CMAKE 3.4开始,您可以执行以下操作:
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
https://cliutils.gitlab.io/modern-cmake/chapters/features/utilities.html
https://modern-cmake-cn.github.io/Modern-CMake-zh_CN/chapters/features/utilities.html
CCache
Set the CMAKE_<LANG>_COMPILER_LAUNCHER
variable or the <LANG>_COMPILER_LAUNCHER
property on a target to use something like CCache to "wrap" the compilation of the target. Support for CCache has been expanding in the latest versions of CMake. In practice, this tends to look like this:
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
set(CMAKE_CUDA_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") # CMake 3.9+
endif()
建议直接修改linux.toolchain.cmake 中的配置
find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) message(STATUS "Set up ccache ...") set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") endif()
https://crascit.com/2016/04/09/using-ccache-with-cmake/
https://github.com/xizhibei/blog/issues/145
生成map文件
SET(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-Map=${CMAKE_PROJECT_NAME}.map") SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -Wl,-Map=${CMAKE_PROJECT_NAME}.map")
https://www.cnblogs.com/sinferwu/p/15353427.html
linux.toolchain.cmake
cmake_minimum_required( VERSION 2.6.3 ) set(CMAKE_SYSTEM_NAME Linux ) set(CMAKE_BUILD_TYPE DEBUG) SET (CMAKE_C_COMPILER "/usr/bin/clang") SET (CMAKE_C_FLAGS "-Wall -std=c99") SET (CMAKE_C_FLAGS_DEBUG "-O0 -g") SET (CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG") SET (CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG") SET (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g") SET (CMAKE_CXX_COMPILER "/usr/bin/clang++") SET (CMAKE_CXX_FLAGS "-Wall") SET (CMAKE_CXX_FLAGS_DEBUG "-O0 -g") SET (CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") SET (CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") SET (CMAKE_AR "/usr/bin/llvm-ar-10") SET (CMAKE_LINKER "/usr/bin/llvm-ld-10") SET (CMAKE_NM "/usr/bin/llvm-nm-10") SET (CMAKE_OBJDUMP "/usr/bin/llvm-objdump-10") SET (CMAKE_RANLIB "/usr/bin/llvm-ranlib-10")
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).
-
4Why don't you just symlink gcc to ccache? And if you're distributing this, I'd think that the user himself would have done the symlink if he had ccache installed and wanted it to be used..– int3Nov 29, 2009 at 14:46
-
1@int3 Yes probably that would work (I was not aware that ccache has the compiler as an optional argument). However it would be cleaner to be more explicit.– amit kumarNov 29, 2009 at 15:00
10 Answers
As of CMAKE 3.4 you can do:
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
-
2And
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
. These work beautifully! I do not know why cmake insists on findingclang
from/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
(so the symlink trick does not work), rather than from$PATH
, but your answer works anyway. May 9, 2017 at 7:56 -
6This should be the best answer. No more messing with path variable and compiler symlinks!– ilya b.Apr 9, 2018 at 13:59
-
2I tried this, but it just gives me the error "ccache: error: Recursive invocation (the name of the ccache binary must be "ccache")". Looking at the verbose trace, it is trying to run "/usr/local/bin/ccache ccache /usr/bin/c++"... Feb 17, 2019 at 20:19
-
7
-
1@ThuongVo anyone who is familiar with cmake knows that -D is a prefix for an option passsed as a CLI parameter. So, given the context of the question, it is somewhat clear to use this when invoking cmake (on configuration that is) Aug 16, 2022 at 7:17
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)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) # Less useful to do it for linking, see edit2
endif(CCACHE_FOUND)
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.
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.
Edit2: @Emilio Cobos recommended to avoid doing that for the linking part as ccache doesn't improve linking speed and can mess with other types of cache like sccache
-
Many sites implicitly advice using doublequotes like in
find_program(CCACHE_FOUND "ccache")
, I don't know which one is more portable, my mileage did perfectly fine without the need for the doublequotes.– 1737973Jun 16, 2015 at 11:33 -
6It's worth noting that this currently only works for Makefile generators (as of cmake 3.3.2). See the manual page of
cmake-properties
. Oct 5, 2015 at 14:34 -
1It is worth noting that this conflicts with the CTEST_USE_LAUNCHERS setting. Those properties are set here too: github.com/Kitware/CMake/blob/master/Modules/… May 15, 2018 at 11:52
-
I think you may want to change the code to this one (except, remove text from inside of
endif()
). The improvements are: 1. There's a configuration option to disable it, and 2. Turns out, colors disappear from GCC/Clang in Make backend when used this way. Theninja
backend works around it by adding-fdiagnostics-color
option, so it's advisable to do so formake
backend too.– Hi-AngelOct 6, 2019 at 12:30 -
1From the docs: This property is intended for internal use by
ctest(1)
. Projects and developers should use the<LANG>_COMPILER_LAUNCHER
target properties or the associatedCMAKE_<LANG>_COMPILER_LAUNCHER
variables instead. Sep 1, 2022 at 14:26
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.
-
11Note that this ccache path has to be placed before the path where your real compiler is in
$PATH
for it to work. Something likeexport PATH = /usr/lib/ccache:$PATH
– Gui13Feb 24, 2011 at 17:06 -
7@Gui13: Better than updating the PATH would be to tell cmake explicitly where the gcc it should use is, e.g. cmake -DCMAKE_CXX_COMPILER=/usr/lib/ccache/bin/g++– cibApr 29, 2014 at 14:36
-
3After
brew install ccache
, I have/usr/local/Cellar/ccache/3.2.1/libexec/
. Oct 19, 2015 at 17:08
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.
-
I also needed the
set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_C_COMPILER}") set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_CXX_COMPILER}")
from the mentioned article. Jan 10, 2018 at 6:19 -
Thanks for the reminder, I've updated the answer to include setting LD and LDPLUSPLUS. Jan 10, 2018 at 19:56
-
ccache does not support VS compilers, so you can't use it for that. There is a project called clcache which aims to provide the same functionality for VS, but I can't comment on how well it works. May 31, 2019 at 22:15
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...
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).
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!
-
Thanks I didn't know about
update-ccache-symlinks
, I was creatingc++
link with a script for a project and it was working but not for another project (still don't know why, the link was fine),update-ccache-symlinks
solved.– AlexMay 29, 2019 at 12:31
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 ...
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
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