[question] CMakeDeps + CmakeToolchain collision with package find modules
See original GitHub issueIs there a way to tell CMakeDeps
to not generate a config file for certain dependencies from the consumer side? Also is there a way to make the CMakeToolchain
add the package paths to the module path, like cmake_paths
generator did?
I’m using the package for pybind11
, which ships its own pybind11-config.cmake
, which contains useful macros. I’m also seeing a file by the same name generated via the CMakeDeps
, of course without the macros. The toolchain only appends CMAKE_BINARY_DIR
to the module path, so the generated one is found when I need to find the one within the package.
More generally:
CMake’s find_package
searches the module path to find FindFoo.cmake
or Foo-config.cmake
. In the context of conan (assuming I want to only find conan packages, not system-installed libs), there are a few places such files would normally be found:
- Within the CMakes installation’s modules folder
- Within a conan package folder in the cache. This is the case if:
- The library itself provides its own
Foo-config.cmake
. Mature libraries based on CMake are advised to provide this. - The recipe for
Foo
exports aFindFoo.cmake
.
- The library itself provides its own
- Within
CMAKE_BINARY_DIR
whenCMakeDeps
generator is used
When using CMakeDeps
+ CMakeToolchain
, only the last one is effectively possible. Other generators, like cmake_paths
add package folders to the module path, but this is no the case with CMakeDeps
+ CMakeToolchain
. However, conan intends to sunset cmake_paths
and other cmake generators in favor of CMakeDeps
.
The config files within the package should take precedent because it has been specialized for the particular package and provides necessary macros. To enable this, I believe CMakeToolchain
needs to add the package folders to the module path, like cmake_paths
does, and CMakeDeps
needs a way to be prevented from generating config files for individual packages.
You could consider this partly a bug in the recipe for Foo
. The recipe should set self.cpp_info.set_property("skip_deps_file", True)
if it is providing its own config file. However, it would be super convenient to affect this from the consumer side so I don’t have to fork the recipe. Even after that, I have to do some manual steps to get the Foo
package folder in the module path.
Less critically, I’d also expect that the default find-modules in the cmake installation should take precedent over the generated config files. CMakeToolchain
has defeated this by setting set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
. I believe I can override this in my generate
method, but I’m surprised the default is to take the generated config files over the handcrafted ones.
- I’ve read the CONTRIBUTING guide.
Issue Analytics
- State:
- Created 2 years ago
- Comments:11 (7 by maintainers)
Thanks @lasote!
I’d like to explore this further. I’d agree that the config file generated by
CMakeDeps
has an advantage in knowing where the dependencies are located and potentially useful info about transitive dependency locations. However, I’d argue that the strongest config file is the one provided by the library itself, which lives in the package itself and where the library author knew exactly what to export/import. CMake recommends that all libraries export a config file. The next strongest is a config file provided by a recipe for that library, since the recipe author has to know details about the library anyway to fill outpackage_info
. In both cases, authors can provide library-specific details that the generator can’t.It is problematic that cmake best-practice strongly recommends authors provide their own config file yet conan (which is defacto cmake-focused) circumvents this practice with a more general replacement. Although I see benefit in the
CMakeDeps
generated one, I don’t think it’s acceptable to indiscriminately prevent the use of the specialized config files provided by the authors. At least, there should be ways to control the generator from the consumer side to elect one or the other.Given that
pybind11
is a very well-done cmake library already and its current recipe in conan center is completely adequate, it is a design smell that I would need to fork one or the other in order to consume. I agree, it makes sense that thepybind11
recipe knows whether or not it exports is own config file and could indicate that, but it seems wrong to force the consumer one way or another. What is generated should be controlled at the consumer level.I have tried it both ways. Unfortunately these workarounds don’t work. In either case, I still have the issue that the path to the config file is not in the prefix path, like it would be if I were using
conan_paths
generator. I could try and force theCMAKE_PREFIX_PATH
variable in the toolchain from thegenerate
method, but there is no way to handle mutli-configuration conan installs from thegenerate
method: the toolchain gets regenerated with each individualconan install
, so I don’t have a way to do something like:because
conan install
doesn’t know both<path to debug package>
and<path to release package>
in any singleconan install
invocation.CMakeDeps
is supposed to be the way forward to handle cmake, including multi-configuration builds. Any suggestions on how to handle this?@kenfred Yeah, it does sound like the visitor pattern would be a good paradigm for improving extensibility. A good test is probably whether support for Google Sanitizers can be used across a project and its dependencies without having to reach into dependencies’ recipes.