With this CMake code snippet from boost/tools/cmake I can install i.e Boost::any lib with HEADERS and CXX_MODULES.
But it fails, if there is more than one FILE_SET used in a library target!
if(NOT CMAKE_VERSION VERSION_LESS 3.28)
get_target_property(INTERFACE_CXX_MODULE_SETS ${LIB} INTERFACE_CXX_MODULE_SETS)
if(INTERFACE_CXX_MODULE_SETS)
boost_message(DEBUG "boost_install_target: '${__TARGET}' has INTERFACE_CXX_MODULE_SETS=${INTERFACE_CXX_MODULE_SETS}")
set(__INSTALL_CXX_MODULES FILE_SET ${INTERFACE_CXX_MODULE_SETS} DESTINATION ${CMAKE_INSTALL_DATADIR})
endif()
endif()
if(NOT CMAKE_VERSION VERSION_LESS 3.23)
get_target_property(INTERFACE_HEADER_SETS ${LIB} INTERFACE_HEADER_SETS)
if(INTERFACE_HEADER_SETS)
boost_message(DEBUG "boost_install_target: '${__TARGET}' has INTERFACE_HEADER_SETS=${INTERFACE_HEADER_SETS}")
set(__INSTALL_HEADER_SETS FILE_SET ${INTERFACE_HEADER_SETS})
endif()
endif()
install(TARGETS ${LIB} EXPORT ${LIB}-targets
# explicit destination specification required for 3.13, 3.14 no longer needs it
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
# explicit needed if used starting with cmake v3.28
# XXX FILE_SET CXX_MODULES DESTINATION "${CMAKE_INSTALL_DATADIR}"
${__INSTALL_CXX_MODULES}
# Any module files from C++ modules from PUBLIC sources in a file set of type CXX_MODULES will be installed to the given DESTINATION.
# explicit needed if used starting with cmake v3.23
# XXX FILE_SET HEADERS
${__INSTALL_HEADER_SETS}
)
Multiple install(TARGETS) calls for the same target are allowed
Each call installs only the referenced file set
CMake merges them internally
This is undocumented, but confirmed by Kitware developers in practice.
CMake Error at cmake/beman-install-library-config.cmake:134 (install):
install TARGETS target beman.execution_headers is exported but not all of
its interface file sets are installed
Call Stack (most recent call first):
CMakeLists.txt:78 (beman_install_library)
CMake Error at cmake/beman-install-library-config.cmake:134 (install):
install TARGETS target beman.execution_headers is exported but not all of
its interface file sets are installed
Call Stack (most recent call first):
CMakeLists.txt:78 (beman_install_library)
CMake Error at cmake/beman-install-library-config.cmake:152 (install):
install TARGETS target beman.execution_headers is exported but not all of
its interface file sets are installed
Call Stack (most recent call first):
CMakeLists.txt:78 (beman_install_library)
-- Configuring incomplete, errors occurred!
I’m aware, that doesn’t explain the use case here. There’s no reason the central infrastructure used by Beman and boost preclude projects from expressing the file sets associated with a given target
If a target does not have a file set, the project owning that target will not list any file sets in the project’s call to install(). If a target has more than one file set, the project owning that target will list all the INTERFACE file sets in that project’s call to install().
The person writing the install() command for a given target needs to know what the target is, what artifacts are associated with the target, and where they wish those artifacts to be installed. There is no way around this. That’s why we leave it to the project to call install().
I wouldn’t. In the same way any wrapper of the install() command needs to accept the list of targets from the project calling the wrapper, it also needs to accept the list of file sets.
Then don’t, and have projects use install() directly. Or only wrap the parts you care about and forward the rest of ARGN directly to install() so projects can handle their file sets on their own.