I have the following CMake code for a header only library that uses FILE_SET.
My question is what is the optimal DESTINATION
for the CMake config file generated.
It’s unclear to me what it should be for a header only library from looking at the documentation.
cmake_minimum_required(VERSION 3.23...3.26)
project(HEADER_ONLY LANGUAGES CXX)
add_library(bar INTERFACE)
add_library(foo::bar ALIAS bar)
target_sources(bar PUBLIC
FILE_SET bar_file_set
BASE_DIRS include
TYPE "HEADERS"
FILES include/bar.h
)
if (PROJECT_IS_TOP_LEVEL)
include(GNUInstallDirs)
install(TARGETS bar EXPORT barConfig FILE_SET bar_file_set)
install(EXPORT barConfig NAMESPACE "foo::" DESTINATION ?)
endif()
You can pick any location that would be searched by the default find_package()
search path. My typical recommendations are:
- If the package contains binaries, then config files should be associated with the architecture-specific library subdirectory. On multi-architecture platforms, this matters because packages may be co-located under a common prefix, but libraries get installed to architecture-specific subdirectories below
lib
. To handle this in a convenient way, I put the package config files in ${CMAKE_INSTALL_LIBDIR}/cmake/<packageName>
, where ${CMAKE_INSTALL_LIBDIR}
is provided by the GNUInstallDirs
module.
- For packages that do not produce binaries (e.g. packages that provide CMake targets that are header-only libraries), it may be better to put the package config files in an architecture-independent location. For this,
share/cmake/<packageName>
may be more suitable.
Note that whatever you choose, package managers may force the use of something else anyway in their own recipes. For example, from what I recall, vcpkg will force all scenarios to use share/cmake/<packageName>
. You don’t need to follow that in your own project, but do be aware that your choice may not be respected by others who repackage your project.
2 Likes
Gotcha, looking at GNUInstallDirs
that translates to: ${CMAKE_INSTALL_DATADIR}/cmake/<packageName>
DATAROOTDIR
read-only architecture-independent data root (share)
DATADIR
read-only architecture-independent data (DATAROOTDIR)
I was originally tempted to use ${CMAKE_INSTALL_DATADIR}
in my previous answer too, but that’s not what you want. The path searched by find_package()
is share
, it can’t be something else. The situation for ${CMAKE_INSTALL_LIBDIR}
is different because that is meant to handle cases like lib/some-arch-specific-subdir
. There is no equivalent for share
, so it has to literally be share
, not whatever ${CMAKE_INSTALL_DATADIR}
evaluates to.
2 Likes
Thanks for the clarification. I’m updating our header only libraries to use share/cmake/<packageName>
.
I guess it was working fine since DATADIR
was defaulting to share
. However, from experience I know package managers can change these variables to suit their own means.