We have a library which has several dependencies: some optional, some required, some bundled. Our package config file looks something like:
include(CMakeFindDependencyMacro)
find_dependency(foo)
if (@PROJECT_HAS_BAR@)
find_dependency(bar)
endif()
foo is required, so we give an option DOWNLOAD_FOO to call FetchContent, but users may use their own built foo instead.
When building our library, users might configure it with -DDOWNLOAD_FOO=on -DUSE_BAR=on -Dbar_ROOT=/path/to/bar.
Now, when consuming our library, users have to tell CMake where to find foo and bar, so we actually also have the following in our -config.cmake:
if (EXISTS "@foo_ROOT@")
set(foo_ROOT "@foo_ROOT@")
elseif (EXISTS "@foo_BINARY_DIR@")
list(APPEND CMAKE_PREFIX_PATH "@foo_BINARY_DIR@")
endif()
if (EXISTS "@bar_ROOT@")
set(bar_ROOT "@bar_ROOT@")
endif()
This way, users don’t need to also supply -Dfoo_ROOT=/path/to/root -Dbar_ROOT=/path/to/root to the downstream project as well. In particular, the correct path for foo_ROOT is not necessarily obvious as it may be buried inside our library’s build directory.
This is of course quite fragile, and has some problems, but I haven’t been able to find how this is best handled. Is there a better way? Should our downstream users just be expected to supply all the same paths and arguments to both projects? That’s not going to make us very popular.