Currently, libraries such as beman::task and beman::net use FetchContent in their CMakeLists.txt files to automatically download their dependencies (beman::execution in the first case, beman::execution and beman::task in the second), even when the library is a subproject itself.
I don’t think this is a good practice. I’ve empirically found that it’s most ergonomic when subprojects don’t try to do anything “clever” about their dependencies, leaving it to the root project to guarantee their acquisition. That is, including beman::net should just link to beman::task and beman::execution, without doing anything else. The top level project would then be responsible for issuing the appropriate FetchContent calls for each library.
(Neither should the CMakeLists.txt files issue find_package. find_package should also be issued by the root project, and the config file for the library would then call find_dependency as appropriate. CMakeLists.txt files should not.)
I agree. beman.exemplar, which is intended to be the model for all beman libraries, will only use FetchContent if the user passes in -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./infra/cmake/use-fetch-content.cmake (or if the root project does something like you’re describing). The issues with beman.task, beman.execution, and beman.net are a result of drift from beman.exemplar, which I will be working toward bringing into alignment.
No, as I said, libraries shouldn’t be calling find_package either in their CMakeLists.txt files when they aren’t the root project.
The root project should call find_package, which will find the installed config file; this config file (and not CMakeLists.txt) would then call find_dependency for the library dependencies.
This isn’t the pattern we want. If find_package fails, and the user doesn’t want to use FetchContent, then using FetchContent as a fallback anyway is a bad default for them; they should just get an error. Users who want FetchContent should have to communicate that explicitly.