cmake, ccache, CCACHE_BASEDIR: wrong paths in compiler error messages

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

cmake, ccache, CCACHE_BASEDIR: wrong paths in compiler error messages

Steffen Dettmer

I hope I can still post here? I don't have a "discourse" account.

Let me summarize what we have here. We have projects with some
hunderds CMakeLists.txt. The "main" typically use several
add_subdirectory directives for the use libraries in form of:

  add_subdirectory(${path_lib_a} liba)

For each, cmake creates a subdirectory (such as here "liba") in the
build directory. Normally cmake uses absolute paths, so compiler error
messages contain absolute paths as well.

Now we are also using ccache. Since we use the same libs in many
places, of course we want to share the ccache results. For multiple
builddirs I was not able to get it working, but at least for the case
of multiple sourcedirs that have there builddirs below. This is useful
if several people work on same code (shared ccache) or if you have
several checkouts, for example for similar variants or source code
branches. In most of these cases, many libraries are the same, so
caching in theory should be very effective.

Since ccache also compares compiler arguments of course and it's
include arguments include absolute paths, ccaching across src trees
does not work, so we have to set CCACHE_BASEDIR. Technically cmake
creates a wrapper file used as CMAKE_CXX_COMPILER_LAUNCHER in BUILDDIR
with "export CCACHE_BASEDIR=$TOPSRCDIR" and then calling essentially
"ccache $CXX "$@"". Now ccache works fine across source trees. At the
end of the mail some cmake excerpt in case it is useful.

But unfortunately now IDEs (like Vim, QTCreator...) are unable to jump
to compiler errors, because now the paths are relative to the
directory where the compiler (wrapper) is called. Normally the IDEs
know this from make output:

  make[2]: Entering directory

but unfortunately for "add_subdirectory", cmake uses some own logic
visible only when running make VERBOSE=1, which looks like:

  make[2]: Entering directory
  [ 14%] Building CXX object....
  cd /home/sdettmer/work/tisc-src/build/cmake-build-debug-1810/libA
    && /home/sdettmer/work/tisc-src/build/cmake-build-debug-1810/ccache-CXX
    -o CMakeFiles/libA.dir/home/sdettmer/work/tisc-src/.../libA/src/File1.cpp.o
     -c /home/sdettmer/work/tisc-src/.../libA /src/File1.cpp

Compiler errrors now are not relative to the path told by make (here
cmake-build-debug-1810), but relative to the "cd .../libA", which is
normally not even visible:

  In file included from ../../...../libA/File1.cpp:10: ....

Now the IDE looks for path relative to cmake-build-debug-1810, because
it does not know about the "cd ...cmake-build-debug-1810/libA" and
does not find the file.

We discussed this in the team, I searched the web for several hours
now, but I don't find any solution. Due to the absolute paths
requirement of cmake I think I must use CCACHE_BASEDIR, but when I do,
IDEs don't find the files. I didn't find a way to make cmake output
"Entering directory" lines. Since we are probably not the only ones
who use cmake and ccache, we probably doing it wrong and miss an
important point.

How is ccache supposed to be used correctly? I saw many examples in
the internet, but none seem to correctly work with CCACHE_BASEDIR, and
without CCACHE_BASEDIR cache is not efficient and almost useless and
shared cache even completely useless (never hits).

Any help appreciated!

As only workaround we could find, I now manually add:

  echo "make[77]: Entering directory '$(pwd)'"

in the ccache-wrapper. This helps a bit, but generates heaps of output
(entering line for each single file) and I think it breaks when using
"make -j".


CMakeLists.txt excerpt:

        foreach(_BT_LANG "C" "CXX")
            file(WRITE "${CMAKE_BINARY_DIR}/ccache-${_BT_LANG}" ""
                "# Xcode generator doesn't include the compiler as the
first arg:\n"
                "[ \"$1\" = \"${CMAKE_${_BT_LANG}_COMPILER}\" ] && shift\n"
                "# \"Convert\" cmake variable to an env to allow
shared caches\n"
                "export CCACHE_BASEDIR=${_BT_CCACHE_BASEDIR}\n"
                "export CCACHE_SLOPPINESS=file_macro,time_macros\n"
                "# export CCACHE_NODIRECT=set\n"
                "export CCACHE_CPP2=set\n"
                "[ \"\$VERBOSE\" ] && echo \"make[\${MAKELEVEL:-1}]:
Entering directory '$(pwd)'\"\n"
\"${CMAKE_${_BT_LANG}_COMPILER}\" \"$@\"\n"
                "[ \"\$VERBOSE\" ] && echo \"make[\${MAKELEVEL:-1}]:
Leaving directory '$(pwd)'\"\n"
            execute_process(COMMAND chmod a+rx
                if (${CXX_FLAG_DIAGNOSTIC_COLOR_AUTO})
                  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=auto")
                  set(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS}
            set(CMAKE_C_COMPILER_LAUNCHER   "${CMAKE_BINARY_DIR}/ccache-C")

Powered by

Kitware offers various services to support the CMake community. For more information on each offering, please visit

Visit other Kitware open-source projects at

Follow this link to subscribe/unsubscribe:

This mailing list is deprecated in favor of