c++visual-studio-codecmake

cmake compile_commands.json for interface target


I have a simple c++ library that should be shipped as header-only library. The library depends on other libraries installed through CPM.

I'm using VS code and the compile_commands.json in order to notify VS code about the include paths from CPM packages. That does work as long as the project is configured as shared/static library or binary. When using an INTERFACE target it however doesn't work anymore (compile_commands.json is generated but VS code shows include paths errors).

How do I use compile_commands.json with an interface target (header-only library) ?

The configuration below does work when defining binary target ( replacing INTERFACE with PUBLIC)!

CMakeLists.txt:

cmake_minimum_required(VERSION 3.21 FATAL_ERROR)

project(CpmCompileCommandsBug
    LANGUAGES CXX
)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

include(cmake/CPM.cmake)

CPMAddPackage(
    NAME yaml-cpp
    VERSION 0.6.3
    GITHUB_REPOSITORY jbeder/yaml-cpp
    GIT_TAG yaml-cpp-0.6.3
    OPTIONS
        "YAML_CPP_INSTALL ON"
)

add_library(${PROJECT_NAME} INTERFACE)
target_link_libraries(${PROJECT_NAME} INTERFACE yaml-cpp)

# the below target config does work
# add_library(${PROJECT_NAME} STATIC main.cpp)
# target_link_libraries(${PROJECT_NAME} PUBLIC yaml-cpp)

main.cpp:

#include <yaml-cpp/yaml.h>

Solution

  • It turns out I was simply using the wrong target. Interfaces don't include any source files and thus won't generate any meaningful compile_commands.json.

    What I was looking for is the object target which solves my issue completely.

    Just for the reference, this is how the "correct" CMakeLists.txt would look like:

    cmake_minimum_required(VERSION 3.21 FATAL_ERROR)
    
    project(CpmCompileCommandsBug
        LANGUAGES CXX
    )
    set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    
    include(cmake/CPM.cmake)
    
    CPMAddPackage(
        NAME yaml-cpp
        VERSION 0.6.3
        GITHUB_REPOSITORY jbeder/yaml-cpp
        GIT_TAG yaml-cpp-0.6.3
        OPTIONS
            "YAML_CPP_INSTALL OFF"
    )
    
    # using OBJECT instead of INTERFACE allows passing source files
    add_library(${PROJECT_NAME} OBJECT main.cpp)
    target_link_libraries(${PROJECT_NAME} PUBLIC yaml-cpp)