Copy file on every cmake command

I use VS Code together with compile_commands.json and my extension / language server needs to know where the compile_commands.json lives.

The problem is that I use multiple build directories / presets and therefore the path to compile_commands.json is not static.

My idea is basically to always copy the “active” compile_commands.json in the root folder, so the path is always static.

I do want the current active compile_commands.json as fast as possible, therefore it should be copied on as much cmake commands as possible.

cmake -B build → Should copy the file
cmake --build build → Should copy the file
cmake --build build --target target → Should copy the file
ctest ... → Ideally should copy the file as well

I know of some ways to copy files as part of a target or post target.

But I don’t know an easy way. I don’t want to specify a post build for every target I have (What’s about targets like install, which are generated automatically …).

So what could be the best and easiest way to achieve that?

You can sort of make this work by doing:

set(output "${CMAKE_SOURCE_DIR}/compile_commands.json")
if (EXISTS "${output}")
  # Add a dependency on the file to CMake so that if it changes, CMake reruns (which should happen on any non-`/fast` target.
  file(READ "${output}" ignored)
  unset(ignored) # Drop the memory
endif ()
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# This *might* work. I don't know if `compile_commands.json` is guaranteed to be written before `file(GENERATE)` runs. If not…I don't know what else might run this late.
file(GENERATE
  INPUT "${CMAKE_BINARY_DIR}/compile_commands.json"
  OUTPUT "${output}")

This almost certainly makes some odd behaviors come up with CMake rerunning “unnecessarily” and as such I’d recommend guarding this behind an “I’m a developer” flag of some kind.