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?