Best practice setting package paths for `find_dependency` in `-config.make` files?

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.

1 Like

when consuming our library, users have to tell CMake where to find foo and bar

From my experience, that is how things should work, so this is to be expected and should not come as a surprise to users. Having find_dependency() calls in one’s package CMake config is sufficient.

I certainly would not try to “guess” the paths to dependencies for users, I don’t see how that would work, unless users are somehow operating on that same host with all the same paths.

I like the idea and totally get the sentiment - when library had 10 dependencies to be built and to use it later you also need to provide them all over again. But not sure how to organize this properly.

Maybe some kind of list of _ROOT paths should be exported, but to a separate file, next to -config.cmake - so it can can be always discarded to keep hardcoded absolute paths out of the installation.
And this auto-find feature preferably should be opt-in since it might confuse typical cmake user - to avoid situations when user is providing dependencies using PATH as usual, but installation keeps preferring some cached path.
Or maybe user can enable it during installation, not during package consumption, but it creates a precedent when the same installed package might behave differently, which is probably better to avoid.