How to Use CCache with CMake? - c++

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).

As of CMAKE 3.4 you can do:
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache

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

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.

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 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!

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

Related

How to add preprocessor definitions on CMake's command line? [duplicate]

I try to set a preprocessor macro in the command line of CMake. I've tried:
set generator="Visual Studio 8 2005"
set params=-D MY_MACRO=1
cmake.exe -G %generator% %params% ..\some_project
but it's neither defined when I compile nor can I find the name MY_MACRO in the files generated by CMake at all, except for CMakeCache.txt where it's present in the form:
MY_MACRO:UNINITIALIZED=1
How can I do it?
A good alternative would be to define a cmake option:
OPTION(DEFINE_MACRO "Option description" ON) # Enabled by default
Followed by a condition:
IF(DEFINE_MACRO)
ADD_DEFINITIONS(-DMACRO)
ENDIF(DEFINE_MACRO)
Then you can turn that option ON/OFF via command line with cmake using the -D flag. Example:
cmake -DDEFINE_MACRO=OFF ..
To make sure the compiler is receiving the definition right, you can call make in verbose mode and check for the macro being defined or not:
make VERBOSE=1
This is a good solution also because make will recompile your code when any of cmake options changes.
Try this: -D CMAKE_CXX_FLAGS=/DMY_MACRO=1
The motivation behind the question was to batch build 3rd party libraries, which is why I wanted to avoid modifying CMakeLists. So years later, even though I don't need that anymore, I figured out that it's easily achievable by means external to CMake:
Invoke CMake as usual, no special flags.
Then:
With MSVC: The compiler reads the CL environment variable to get extra command line arguments. So
set CL=/DMY_MACRO=1 %CL%
then invoke MSBuild to do its job.
With Makefiles: The generated makefiles use the CFLAGS and CXX_FLAGS variables as makefiles are expected to do. So the build can be started by
make CXX_FLAGS=-DMY_MACRO=1
or by setting the corresponding environment variables.
Unless you have a good reason not to, you should use ADD_DEFINITIONS(<name>=<value>[, ...]).
Just add the following line to your CMakeLists.txt:
ADD_DEFINITIONS("MY_MACRO=1")
CMake will take care of the syntax of the switches (be it -D<name>=<value>, or /D<name>=<value>).

Compiling Tensorflow with a custom Clang + Libc++ (instead of stdlibc++)

I am trying to compile tensorflow with a custom clang/llvm toolchain and using clang's native libc++ (instead of borrowing Gcc's stdlibc++).
It looks like bazel plain assumes that every clang will use Gcc's libraries because I get these errors:
$ bazel build --cxxopt=-std=c++11 --cxxopt=-stdlib=libc++ tensorflow:libtensorflow.so
INFO: Found 1 target...
INFO: From Compiling
external/protobuf/src/google/protobuf/compiler/js/embed.cc [for host]:
external/protobuf/src/google/protobuf/compiler/js/embed.cc:37:12:
warning: unused variable 'output_file' [-Wunused-const-variable]
const char output_file[] = "well_known_types_embed.cc";
^
1 warning generated.
ERROR: /home/hbucher/.cache/bazel/_bazel_hbucher/ad427c7fddd5b68de5e1cfaa7cd8c8cc/external/com_googlesource_code_re2/BUILD:11:1: undeclared inclusion(s) in rule '#com_googlesource_code_re2//:re2':
this rule is missing dependency declarations for the following files included by 'external/com_googlesource_code_re2/re2/bitstate.cc':
'/home/hbucher/install/include/c++/v1/stddef.h'
'/home/hbucher/install/include/c++/v1/__config'
I tried to hack into tools/cpp/CROSSTOOL inside bazel as some posts suggested to add the line
cxx_builtin_include_directory: "/home/hbucher/install/include/c++/v1"
but to no avail, it does not seem to make any difference.
Then I tried to follow a bazel tutorial to create a custom toolchain. The text does not help much because they are actually writing a cross tool while what I am trying to do is to tweak the existing host rules and somehow bazel seems to undo every attempt I try to tweak its parameters.
I have got to the point that is currently in my github repository https://github.com/HFTrader/BazelCustomToolchain
However it does not compile and I cannot even figure out how to start debugging this message.
$ bazel build --crosstool_top=#hbclang//:toolchain tensorflow:libtensorflow.so
.....................
ERROR: The crosstool_top you specified was resolved to
'#hbclang//:toolchain', which does not contain a CROSSTOOL file. You can
use a crosstool from the depot by specifying its label.
INFO: Elapsed time: 2.216s
I have appended these lines to my tensorflow/WORKSPACE
new_local_repository(
name="hbclang",
path="/home/hbucher/BazelCustomToolchain",
build_file = "/home/hbucher/BazelCustomToolchain/BUILD",
)
I have asked this question on bazel's google groups but they redirected me to stackoverflow. At this point I am about to give up.
Have someone attempted to do this or I'm breaking ground here?
Thank you.
Solved. Not in the intended way but it works for me.
export INSTALL_DIR="$HOME/install"
export CC=$INSTALL_DIR/bin/clang
export CXX=$INSTALL_DIR/bin/clang++
export CXXFLAGS="-stdlib=libc++ -L$INSTALL_DIR/lib"
export LDFLAGS="-L$INSTALL_DIR/lib -lm -lrt"
export LD_LIBRARY_PATH="/usr/lib:/lib/x86_64-linux-gnu/:$INSTALL_DIR/lib"
git clone https://github.com/tensorflow/tensorflow.git tensorflow-github
cd tensorflow-github
mkdir build-tmp && cd build-tmp
cmake ../tensorflow/contrib/cmake/
make -j4
Easy as 1-2-3 with cmake
[2020-05-24: Edit to make the answer up to date.]
TLDR: To build a project with Bazel with a specific Clang binary, and with libc++, this works for me (where INSTALL_DIR is where I've installed llvm):
CC="$INSTALL_DIR/bin/clang" \
BAZEL_CXXOPTS="-stdlib=libc++:-isystem$INSTALL_DIR/include" \
BAZEL_LINKOPTS="-stdlib=libc++" \
BAZEL_LINKLIBS="-L$INSTALL_DIR/lib:-Wl,-rpath,$INSTALL_DIR/lib:-lc++:-lm" \
bazel test //...
Background:
You can use --repo_env option, e.g. --repo_env=CC=clang, to put these defaults into your project- or system-wide .bazelrc.
This approach uses Bazel's C++ toolchain autoconfiguration which doesn't attempt to declare all the toolchain inputs in BUILD files. This is to simplify the configuration for the user. Therefore whenever you modify the C++ toolchain in a way that Bazel cannot know about (rebuild llvm etc.), you have to run bazel clean --expunge to flush the cache and rerun the autoconfiguration the next time.
The robust solution to specifying C++ toolchain in Bazel is to use the CcToolchainConfigInfo. See the documentation at https://docs.bazel.build/versions/master/tutorial/cc-toolchain-config.html and https://docs.bazel.build/versions/master/cc-toolchain-config-reference.html.

Using compiler prefix command(s) with CMake (distcc, ccache)

There are utilities which use an existing compiler by adding a command as a prefix (so instead of calling cc -c file.c you could call distcc cc -c file.c).
When using CMake the compiler command can be changed, however I ran into problems trying to use distcc, though this would likely apply to any command prefix to the compiler (ccache too).
CMake expects the compiler to be an absolute path,so setting CMAKE_C_COMPILER to /usr/bin/distcc /usr/bin/cc, gives an error:
/usr/bin/distcc /usr/bin/cc
is not a full path to an existing compiler tool.
Setting the compiler to /usr/bin/distcc andCMAKE_C_COMPILER_ARG1 or CMAKE_C_FLAGS to begin with /usr/bin/cc works in some cases, but fails with CHECK_C_SOURCE_COMPILES(checked if there was some way to support this, even prefixing CMAKE_REQUIRED_FLAGS didn't work).
The only way I found to do this is to wrap the commands in a shell script.
#!/bin/sh
exec /usr/bin/distcc /usr/bin/cc "$#"
While this works, It would be nice to be able to use compiler helpers with CMake, without having to go though shell scripts (giving some small overhead when the build system could just use a command prefix).
So my question is:
Can CMake use compiler prefix commands (such as distcc) directly?, without shell script wrappers?
Since CMake 3.4.0 there has been a CMAKE_<LANG>_COMPILER_LAUNCHER variable and corresponding target property <LANG>_COMPILER_LAUNCHER. So if your project is C-only you would do something like:
cmake -DCMAKE_C_COMPILER_LAUNCHER=ccache /path/to/source
CCACHE_PREFIX=distcc make -j`distcc -j`
If you have a C++ project, use -DCMAKE_CXX_COMPILER_LAUNCHER=ccache.
Or, make your CMakeLists.txt smart and use ccache automatically if it can be found:
#-----------------------------------------------------------------------------
# Enable ccache if not already enabled by symlink masquerading and if no other
# CMake compiler launchers are already defined
#-----------------------------------------------------------------------------
find_program(CCACHE_EXECUTABLE ccache)
mark_as_advanced(CCACHE_EXECUTABLE)
if(CCACHE_EXECUTABLE)
foreach(LANG C CXX)
if(NOT DEFINED CMAKE_${LANG}_COMPILER_LAUNCHER AND NOT CMAKE_${LANG}_COMPILER MATCHES ".*/ccache")
message(STATUS "Enabling ccache for ${LANG}")
set(CMAKE_${LANG}_COMPILER_LAUNCHER ${CCACHE_EXECUTABLE} CACHE STRING "")
endif()
endforeach()
endif()
Just as a hint: never use <LANG>_COMPILER_LAUNCHER to cross compile. If <LANG>_COMPILER_LAUNCHER is used together with distcc the absolute compiler path is sent to distcc and the host is not using the cross comping toolchain!
Instead you should use the old school method, just overwrite the compiler path:
export PATH=/usr/lib/distcc:$PATH
It took me hours to find out...

Adding include directories to CMake when calling it from the command line

I'm in a situation where I should not disturb the existing CMakeLists.txt files, but I still should add some g++ system include directory to my build.
In other words, I need -isystem /path/to/my/include added to my compiler flags, but when calling something like cmake ...
Maybe something like cmake .. -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS -isystem /path/to/my/include"? Is there a way to do this?
I have the same problem. I found two solutions:
The one proposed by sakra in a previous answer, i.e. setting an environment variable with C++ flags:
export CXXFLAGS=-isystem\ /path/to/my/include
cmake <path to my sources>
OR the same thing, but environment variable are set only for this CMake call:
CXXFLAGS=-isystem\ /path/to/my/include cmake <path to my sources>
IMPORTANT: you must clean your build directory (i.e. clean the CMake cache) before launching any of this form. Without cleaning the cache, CMake will continue using your cached CMAKE_CXX_FLAGS from the previous run.
Directly setting CMAKE_CXX_FLAGS in cmake string:
cmake -DCMAKE_CXX_FLAGS=-isystem\ /path/to/my/include <path to my sources>
I believe that it can be done by a more 'native' way, but I didn't find a variable responsible for paths to headers in CMake.
You can set the environment variable CXXFLAGS before invoking CMake.
$ export CXXFLAGS=-isystem\ /path/to/my/include
$ cmake ..
CMake will the initialize the cache variable CMAKE_CXX_FLAGS with the flags from the environment variable. The variable affects all build types.
Using -DCMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES=<something> worked for me even without toolchain file. This avoids cluttering compiler flags.
Just an additional note to the other answers: with CMake 3.15.3 on macOS 10.14.5, only the solution using the CMake flag seems to work properly.
So, in my case, only this solution worked fine:
cmake -DCMAKE_CXX_FLAGS=-I\ /path/to/include <path/to/source>

CMake coloring errors and warnings

Is there a way how to produce a colorful output from gcc which is called from Makefile generated by cmake? It would make debugging application a lot easier.
Do you want colourful output from cmake binary? For that I don't know any solution.
CMake can generate Makefiles that provide verbose (and colourful) information about the build process. This can be enabled in the following way:
SET(CMAKE_COLOR_MAKEFILE ON)
# And optionally
SET(CMAKE_VERBOSE_MAKEFILE ON)
If you want to have the gcc output colourised, then have a look at colorgcc perl script. Having it installed try something like this:
CC=/usr/bin/colorgcc cmake .....
Or use the newer solution proposed in another answer by gfour - the gccfilter
Other tools are not necessary now. GCC and Clang produce color output but hide it when they detect they're being used in a pipeline like CMake Makefiles use. They have flags to force color though.
CMakeLists.txt:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
add_compile_options(-fdiagnostics-color=always)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_compile_options(-fcolor-diagnostics)
endif()
If you do pipe the output of make sometimes, you can put this behind a flag.
Color output preview:
Reference:
https://medium.com/#alasher/colored-c-compiler-output-with-ninja-clang-gcc-10bfe7f2b949
Download gccfilter (needs perl, libregexp and libgetopt-argvfile), then run:
gccfilter -c cmake ...
This will colorize the messages from the build process (which I assume are gcc mesages).
Try colout, it is designed to seamlessly color the output of any command, and comes with a g++ AND a cmake theme, which you can use together:
make something 2>&1 | colout -t cmake | colout -t g++
Besides improving the cmake colorscheme, it even applies syntax coloring on the code printed out by g++.
Since CMake v3.24, there is the CMAKE_COLOR_DIAGNOSTICS variable. Follow that link for the most up-to-date version of the docs. Here is a quote from the 3.24.2 docs:
Enable color diagnostics throughout.
This variable uses three states: ON, OFF and not defined.
When not defined:
Makefile Generators initialize the CMAKE_COLOR_MAKEFILE variable to ON. It controls color buildsystem messages.
GNU/Clang compilers are not invoked with any color diagnostics flag.
When ON:
Makefile Generators produce color buildsystem messages by default. CMAKE_COLOR_MAKEFILE is not initialized, but may be explicitly set to OFF to disable color buildsystem messages.
GNU/Clang compilers are invoked with a flag enabling color diagnostics (-fcolor-diagnostics).
When OFF:
Makefile Generators do not produce color buildsystem messages by default. CMAKE_COLOR_MAKEFILE is not initialized, but may be explicitly set to ON to enable color buildsystem messages.
GNU/Clang compilers are invoked with a flag disabling color diagnostics (-fno-color-diagnostics).
If the CMAKE_COLOR_DIAGNOSTICS environment variable is set, its value is used. Otherwise, CMAKE_COLOR_DIAGNOSTICS is not defined by default.
Based on this discussion I've created an alias in ~/.bashrc for make:
alias make="make VERBOSE=1 2>&1 | sed -e 's%^.*: error: .*$%\x1b[37;41m&\x1b[m%' -e 's%^.*: warning: .*$%\x1b[30;43m&\x1b[m%'"
it's not really nice solution, but it does the job.