Does @mherok’s reply still remain the best way to go about this?
In any case, I had to update his code a bit with CMake 3.26. Here’s what seems to work well:
cmake_minimum_required(VERSION 3.23...3.26)
# ...
target_sources(${PROJECT_NAME} PUBLIC
FILE_SET public_headers
TYPE HEADERS
BASE_DIRS include
FILES include/foobar.h)
include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME} FILE_SET public_headers)