Problems getting CMake to install the HEADERS file set

Given the following CMakeLists.txt:

cmake_minimum_required(VERSION 3.27)

project(gubbins)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN YES)

add_library(gubbins SHARED
    src/lib/gubbins.cpp
)
set_target_properties(gubbins PROPERTIES
    SOVERSION 1
    VERSION 1.1.1
)

include(GenerateExportHeader)
generate_export_header(gubbins)
target_sources(gubbins
    PUBLIC
        FILE_SET HEADERS
        BASE_DIRS
            src/include
            ${CMAKE_CURRENT_BINARY_DIR}
)

include(GNUInstallDirs)
install(TARGETS gubbins FILE_SET HEADERS)

I’m using the Ninja Multi-Config generator, CMake 3.30.5, and ninja 1.12.1. on macOS 14.

I would expect the following sequence of commands to result in build/staging/Release containing include/*.h and lib/*.dylib, but no headers are being installed, just the library files:

$ cmake -G "Ninja Multi-Config" -B build
$ cmake --build build --config Release
$ cmake --install build --config Release --prefix build/staging/Release

(The same happens if I omit --prefix but have set CMAKE_INSTALL_PREFIX in CMakeLists.txt)

I’m quite baffled - I created this new trivial project to test with, after experiencing this with my actual project. I’m assuming I’m doing something daft, but I’m at a loss for what…

The complete test project is at GitHub - fidothe/cmake-install-problem: Minimal repro for CMake install problems I'm having

Any insights gratefully received.

Yes, I was doing something daft.

For some reason I’d got it into my head that this would add all header files in the directories into the HEADERS file set:

target_sources(gubbins
    PUBLIC
        FILE_SET HEADERS
        BASE_DIRS
            src/include
            ${CMAKE_CURRENT_BINARY_DIR}

That added the the directories to the include search path, but didn’t actually add any files to the file set. So, the build succeeded because the preprocessor could find the headers, but the install didn’t install anything, because there wasn’t anything to install…

I needed this:

target_sources(gubbins
    PUBLIC
        FILE_SET HEADERS
        BASE_DIRS
            src/include
            ${CMAKE_CURRENT_BINARY_DIR}
        FILES
            "src/include/gubbins.h"
            "${CMAKE_CURRENT_BINARY_DIR}/gubbins_export.h"

I’ve never used FILE_SET myself before, but I reckon the configuration will fail if you provide just the gubbins.h instead of src/include/gubbins.h? I’ve actually tried that with your example project, and it did fail to configure. But then I don’t get the point of providing BASE_DIRS, since those are duplicated in FILES.

(That is not a question to you but to anyone who’s familiar with the way FILE_SETs are supposed to work).