Akshit Sharma
Akshit Sharma

Reputation: 71

Copy compile_commands.json to project root folder

I have a CMakeLists.txt in the root of my project with CMAKE_EXPORT_COMPILE_COMMANDS turned on.

I am building target inside a folder and is called via add_subdirectory. The folder has its own CMakeLists.txt file.

compile_commands.json is built in the root of the binary directory, and I want to copy it to root of source directory after running the cmake command.

I have tried two approaches.

  1. add_custom_target and add_custom_command. I created a dummy target. I used this target for add_custom_command to copy the file but it does not trigger command in add_custom_command.

  2. file(COPY ...) The first time the command is triggered, the compile_commands.json is not created via cmake. I don't want to run cmake command twice to get copy compile_commands.json to root of source folder.

CMAKE_MINIMUM_REQUIRED(VERSION 3.8)
project(exec LANGUAGES CXX)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

add_subdirectory("DirectoyWithTarget")

add_custom_target(copy_compile_commands
  DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/compile_commands.json)
add_custom_command(
  TARGET copy_compile_commands
  PRE_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy_if_different
    ${CMAKE_CURRENT_BINARY_DIR}/compile_commands.json
    ${CMAKE_CURRENT_SOURCE_DIR}/compile_commands.json
  )   

The compile_commands.json file is not copied to ${CMAKE_CURRENT_SOURCE_DIR}. This means the add_custom_command is not triggered.

Upvotes: 7

Views: 5727

Answers (3)

starball
starball

Reputation: 51038

You also have the option to create a symlink. See the file(CREATE_LINK ...) command. Ex.

file(CREATE_LINK
  "${CMAKE_BINARY_DIR}/compile_commands.json"
  "${CMAKE_SOURCE_DIR}/compile_commands.json"
  SYMBOLIC
)

The advantage of that would be that you only have to do it once. It's pretty simple to do, and you wouldn't need to update contents when compile_commands.json changes.


If you're using CMake Tools + VS Code, see also the cmake.copyCompileCommands setting.

If you're using clangd and VS Code, see also https://stackoverflow.com/a/76214731/11107541.

Upvotes: 4

grifcj
grifcj

Reputation: 433

Haven't tested these much, but here are two cmake based solutions I came up with.

Option 1

Less code, but always runs.

add_custom_target(
    copy-compile-commands ALL
    ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_BINARY_DIR}/compile_commands.json
        ${CMAKE_CURRENT_LIST_DIR}
    )

Option 2

More code, but sets up dependencies so doesn't run unless need to. Can handle case where you delete compile_commands.json in binary directory.

# Copy to source directory
add_custom_target(
    copy-compile-commands ALL
    DEPENDS
        ${CMAKE_CURRENT_LIST_DIR}/compile_commands.json
    )
add_custom_command(
    OUTPUT ${CMAKE_CURRENT_LIST_DIR}/compile_commands.json
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_BINARY_DIR}/compile_commands.json
        ${CMAKE_CURRENT_LIST_DIR}/compile_commands.json
    DEPENDS
        # Unlike "proper" targets like executables and libraries, 
        # custom command / target pairs will not set up source
        # file dependencies, so we need to list file explicitly here
        generate-compile-commands
        ${CMAKE_BINARY_DIR}/compile_commands.json
    )

# Generate the compilation commands. Necessary so cmake knows where it came
# from and if for some reason you delete it.
add_custom_target(generate-compile-commands
    DEPENDS
        ${CMAKE_BINARY_DIR}/compile_commands.json
    )
add_custom_command(
    OUTPUT ${CMAKE_BINARY_DIR}/compile_commands.json
    COMMAND ${CMAKE_COMMAND} -B${CMAKE_BINARY_DIR} -S${CMAKE_SOURCE_DIR}
    )

Upvotes: 7

maidamai
maidamai

Reputation: 722

You can use cmake.copyCompileCommands, if you use vscode and vscode-cmake-tools.

Example:

"cmake.copyCompileCommands": "${workspaceFolder}/compile_commands.json"

Upvotes: 7

Related Questions