I am trying to understand the underlying mechanisms behind dependency management in CMake, particularly with regards to FetchContent. FetchContent can be set up to first call find_package
and if that doesn’t find anything compatible, to download the requested library.
Therefore, my project should be able to depend on two libraries that both depend on, let’s say nlohmann_json. First dependency checks for nlohmann, doesn’t find it, fetches it. Second dependency checks, finds it, does nothing - the linkable target is already available.
Except that is not what I am observing:
include (FetchContent)
FetchContent_Declare( json
GIT_REPOSITORY "https://github.com/nlohmann/json"
GIT_TAG "v3.12.0"
)
FetchContent_MakeAvailable ( json )
find_package( nlohmann_json 3.12 CONFIG REQUIRED)
This yields:
Could not find a package configuration file provided by "nlohmann_json"
(requested version 3.12.0) with any of the following names:
nlohmann_jsonConfig.cmake
nlohmann_json-config.cmake
Add the installation prefix of "nlohmann_json" to CMAKE_PREFIX_PATH or set "nlohmann_json_DIR" to a directory containing one of the above files. If
"nlohmann_json" provides a separate development package or SDK, be sure it
has been installed.
The find_package
lookup will be satisfied when it finds said file, even if said file is empty. nlohmann_json creates this file (alongside the version config file) when configured and it is configured automatically by FetchContent. Therefore, this fixes the problem:
find_package( nlohmann_json 3.12 CONFIG REQUIRED
HINTS "${CMAKE_BINARY_DIR}/_deps/json"
)
But providing this hint means that the one who’s checking knows where the dependency was downloaded in the first place. So I explored further and found that:
find_package(json 3.12 CONFIG REQUIRED)
succeeds! But in a weird way. json_VERSION
is unset and json_DIR
points to ${CMAKE_BINARY_DIR}/CMakeFiles/pkgRedirects
. I wasn’t able to confirm this 100%, but I suspect this somehow relates to PkgConfig and since the version cannot be properly evaluated, this isn’t the intended way of finding the package.
Okay, let’s get back to the original error message - set the <package>_DIR
variable. Since setting any variable won’t survive the current scope and chaining PARENT_SCOPE
doesn’t make sense in this context, I’ve tried setting the variable with CACHE PATH "docstring" FORCE
parameters and miracuously, it worked.
So the question is: Is this the correct, sane, idiomatic way for the library to behave? Should a library called foo
set the cache variable foo_DIR
to the place where it puts config files so FetchContent can reliably find it? Are there other mechanisms to ensure the library will be always found by find_package
in this context?