CCache - same project in different directories

288 views Asked by At

I'm trying to configure CCache with my CMake projects. I intend to use this within my CI/CD system, and am preparing it locally first as a test. I cannot for the life of me get CCache to correctly reuse its cache for the same project when the project itself is in different directories. This is a dealbreaker for me, because in my CI/CD system I have several types of jobs that checkout projects in different directories, including directories with randomly generated names.

What I can get to work partially is different build directories within the project root, for example with a project named foo:

  • foo
    • build_debug_1
    • build_debug_2

but not:

  • projects
    • foo
      • build_debug
  • other_projects
    • foo
      • build_debug

That being said, even in the former case I don't get a 100% cache hit like when rebuilding after nuking the build directory's contents.


It seems to me that CCache also aims to enable multiple users to share a cache, or even multiple servers; unless I'm misunderstanding these use cases (or how to handle it correctly), how could CCache actually hope to achieve this unless all projects are stored in identical filesystems across multiple users/systems?

I hope I'm just doing something wrong.

In CMake, I'm enabling CCache as follows:

find_program(CCACHE_PROGRAM ccache)
if (CCACHE_PROGRAM)
    message(NOTICE "Selected CCache: ${CCACHE_PROGRAM}")
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
    set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_PROGRAM}")
    get_filename_component(PARENT_DIR ${PROJECT_SOURCE_DIR} DIRECTORY)
    set(ENV{CCACHE_BASEDIR} "${PARENT_DIR}")
    set(ENV{CCACHE_SLOPPINESS} "pch_defines,file_macro,include_file_ctime")
    set(ENV{CCACHE_NOHASHDIR} "1")
else ()
    message(WARNING "Could not find ccache, skipping!")
endif ()
3

There are 3 answers

2
Yattabyte On BEST ANSWER

Perhaps @jpr42's answer hits upon the cause of the issue, although a colleague of mine happened upon a solution.

find_program(CCACHE_PROGRAM ccache)
if (CCACHE_PROGRAM)
    message(NOTICE "Selected CCache: ${CCACHE_PROGRAM}")
    set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM} base_dir=${PROJECT_SOURCE_DIR} hash_dir=false)
    set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM} base_dir=${PROJECT_SOURCE_DIR} hash_dir=false)
else ()
    message(WARNING "Could not find ccache, skipping!")
endif ()

I've tested with multiple compilers in different build modes across different directory structures and it worked

1
jpr42 On

The way you are setting environment variables is problematic.

    set(ENV{CCACHE_BASEDIR} "${PARENT_DIR}")
    set(ENV{CCACHE_SLOPPINESS} "pch_defines,file_macro,include_file_ctime")
    set(ENV{CCACHE_NOHASHDIR} "1")

They will only be active during the CMake configuration step.

IE when you actually try building the binaries these environment variables won't be set anywhere.

cmake -S . -B build .... # Your environment variables are set

cmake --build build ... # Your environment variables are NOT set. So ccache won't have been configured.
0
BenPortner On

As previous answers noted correctly, environment variables set during the CMake configuration step will not be available after. To set environment variables for the build step, you can use this hack from Github. In your case:

find_program(CCACHE_PROGRAM ccache)
if (CCACHE_PROGRAM)
    message(NOTICE "Selected CCache: ${CCACHE_PROGRAM}")
    get_filename_component(PARENT_DIR ${PROJECT_SOURCE_DIR} DIRECTORY)
    set(ccacheEnv
            CCACHE_BASEDIR="${PARENT_DIR}"
            CCACHE_SLOPPINESS="pch_defines,file_macro,include_file_ctime"
            CCACHE_NOHASHDIR=true
    )
    set(CMAKE_C_COMPILER_LAUNCHER ${CMAKE_COMMAND} -E env ${ccacheEnv} ${CCACHE_PROGRAM})
    set(CMAKE_CXX_COMPILER_LAUNCHER ${CMAKE_COMMAND} -E env ${ccacheEnv} ${CCACHE_PROGRAM})
endif ()

Edit:

As of Ccache version 4.8, project-specific options can also be passed via a semicolon-separated list:

find_program(CCACHE_PROGRAM ccache)
if (CCACHE_PROGRAM)
    message(NOTICE "Selected CCache: ${CCACHE_PROGRAM}")
    get_filename_component(PARENT_DIR ${PROJECT_SOURCE_DIR} DIRECTORY)
    set(ccacheOpts "${CCACHE_PROGRAM};base_dir=${PROJECT_SOURCE_DIR};hash_dir=false;sloppiness=pch_defines,file_macro,include_file_ctime")
    set(CMAKE_C_COMPILER_LAUNCHER ${ccacheOpts})
    set(CMAKE_CXX_COMPILER_LAUNCHER ${ccacheOpts})
endif ()

More details at the ccache wiki.