Conan: [feature] Custom variables in generated `conan_paths.cmake`

Created on 20 Feb 2020  路  8Comments  路  Source: conan-io/conan

The cmake_paths generators allows us to be the least intrusive when working with Conan.
It works best, when all used packages provide a Config.cmake file.
It can still work reasonably well with the FindScripts that come with CMake, but sometimes only if you set some specific variables to define the search behavior (e.g. don't search in the System).

Concrete example:
I've packaged python3 with Conan. CMake comes with a FindPython3.cmake script which works reasonably well, but it's default behavior is to search for the newest Python version, but not the one it locates first honoring the CMAKE_MODULE_PATH variable generated by the conan paths generator.

As a consumer I can call the following to find the provided Conan package and not my newer system version:

set(Python3_FIND_STRATEGY LOCATION)
find_package(Python3 COMPONENT Development)

But the burden of setting the Python3_FIND_STRATEGY variable should not be on the consumer side, but on the package creator side.
conan_paths.cmake is everything provided to the consumer when working with that generator, so it would be great if I could, in the package_info, specify some additional information to the cmake_paths generator.

Possible syntax (analog to CMake.definitions):

def package_info(self):
  self.cmake_paths_info.definitions["Python3_FIND_STRATEGY"] = "LOCATION"

which translates to

# Regular conan_paths.cmake
set(CMAKE_MODULE_PATH ...)
set(CMAKE_PREFIX_PATH ...)

set(Python3_FIND_STRATEGY "LOCATION")

Is that something you would consider implementing?
Or can this already be achieved?

Could also somewhat be related to #6535

low high queue feature

Most helpful comment

Yes, right now we have the build_modules attribute that is useful to include .cmake files that declare functions, those were added thinking on packages like protobuf or pybind11 that need to deploy custom functions, i.e.: protobuf_generate_cpp or pybind11_add_module... this is a new use-case that totally makes sense.

We need to provide a way to generate/add custom CMake variables to cmake and cmake_find_package generators (the consumer will need to include the generated files via include or find_package). Right now the workaround would be: to generate a .cmake file, add the required set(VAR VALUE) to it, pack it and declare the file in the build_modules. Something built-in make sense.


Linking to https://github.com/conan-io/conan/issues/6125, the same considerations may apply to this feature.

All 8 comments

It'd help with the https://github.com/conan-io/conan-center-index/issues/419

Regarding the syntax:

We could use a syntax closely related to already existing self.cpp_info.build_modules so users would assume that they're related:

self.cpp_info.build_definitions["Python3_FIND_STRATEGY"] = "LOCATION"

We do have the self.cpp_info.names[鈥済enerator鈥漖, to specify generator, which is nice because other possibly user-provided generators can use look them up too. It could be useful for build_modules too, so maybe it's better to move the generator specialization up to self.cpp_info["generator"].<field>?

The self.cpp_info has aggregated a lot of information, which are specific to the consumption of the package, so that is correct. Most information is important for the different generators (Visual Studio, CMake, ...).

But then you have env_info which sets paths, and this information is relevant for all generators which manipulate paths / enviroment variables.

And this should set properties also for a specific generator, this is why I would separate it from cpp_info which is relavant for a lot of build generators.

self.cpp_info.build_definitions["Python3_FIND_STRATEGY"] = "LOCATION"

would be totally irrelevant / won't make sense in this case for any other generator than cmake_paths.
On the other hand I also don't want self.cpp_info.build_modules show up in the cmake_paths
generated stuff, because it's not relevant for that generator.

self.generator_info["cmake_paths"].definitions["Python3_FIND_STRATEGY"] = "LOCATION"

could be more generic.

We could add even some more information for the cmake_paths generator, like the information if a package will be consumed a) in Config mode or b) in Module mode.
You could add this information like

self.generator_info["cmake_paths"].config_mode = True

And depending on this information, cmake_paths would only have to append either CMAKE_MODULE_PATH variable OR CMAKE_PREFIX_PATH variable (now it appends both).

Let's see what the Conan folk thinks.

Hi! The cmake_paths generator has a very specific purpose and IMO we shouldn't add anything else to it. We really think that the package manager should know all the information needed to consume the package, and I agree that the Python3_FIND_STRATEGY shouldn't be something to state in the consumer (unless it wants to override it), and this is something we need to provide for other CMake generators like cmake_find_package[_multi].

Maybe we should have a look at the CMake module for Python3 and see if there is anything else we need to add in order to be able to support your Python3 recipe.... if the build_modules is not enough or it is not the proper way to address these problems. But, I assume that if anyone is using Conan to package Python they'd always want the "LOCATION" strategy and that will be the behavior of the FindPython3.cmake file generated by Conan using the cmake_find_package generator.

Hi @jgsogo,
I think you might have missunderstood me. Since I am working entirely with the cmake_paths generator to stay non-intrusively, Conan is not generating any FindPython3.cmake for me.
Instead I am falling back to using FindPython3.cmake provided with the CMake installation.

I know that you guys discourage the usage of cmake_paths generator for different reasons. I still believe it's a good way to go, when you don't have to support other build systems than CMake. When using that generator, my consumer software knows nothing about Conan. Especially when developing against Python I think that is important, because many people will want to build against their installed, specific Python version and that should work out of the box.

But when I do want to build against a conan package, everything should be induced from the outside, through conan_paths.cmake. But in order to consume the python conan package correctly, I need to have that variable set.

So, I am asking for some syntax to add just a variable to the generated conan_paths.cmake file, the same way that e.g. that any build generator will add some information to the generated files. If you add self.cpp_info.defines = "ABC" it will generate some set(CONAN_PKG_DEFINES "ABC").

Meaning I am asking for for a way to generate a specific CMAKE variable. self.cmake_info.["Python3_FIND_STRATEGY"] = "LOCATION" -> set(Python3_FIND_STRATEGY "LOCATION"). That's it 馃槃

But if you guys say that this is totally out of scope, then it's ok.

We would like to maintain the existing cmake_paths generator as simple as possible, so let's try to find an alternative first:

  • writing a custom generator would be one way to go.
  • or using two generators like cmake_paths and cmake, you can include the later one too (it won't execute anything, it justs set variables and declare functions) and there you can have that variable available.

If you think it can work for you we can think about the best way to propagate that variable to the .cmake file which will be very useful for other recipes.

Hi, thanks a lot for your feedback.

or using two generators like cmake_paths and cmake, you can include the later one too (it won't execute anything, it justs set variables and declare functions) and there you can have that variable available.

If I am using both generators, how would I access this variable? First I'd have to include that generated file, and thus modify the consumers CMakeLists.txt, correct? This is what I am trying to avoid in the first place.

writing a custom generator would be one way to go.

This sounds reasonable, and should be easy enough. It's been awhile since I've played around with custom generators, but even if i do have a cutom generator I fear that I can't just set arbitrary fields on self.cpp_info? Or completely invent new fields that the generator can access?

But I guess, if a new field was introduced to support setting variables for the "cmake" or "cmake_find_package" generators, I can access that variable from a custom generator, too.

Yes, right now we have the build_modules attribute that is useful to include .cmake files that declare functions, those were added thinking on packages like protobuf or pybind11 that need to deploy custom functions, i.e.: protobuf_generate_cpp or pybind11_add_module... this is a new use-case that totally makes sense.

We need to provide a way to generate/add custom CMake variables to cmake and cmake_find_package generators (the consumer will need to include the generated files via include or find_package). Right now the workaround would be: to generate a .cmake file, add the required set(VAR VALUE) to it, pack it and declare the file in the build_modules. Something built-in make sense.


Linking to https://github.com/conan-io/conan/issues/6125, the same considerations may apply to this feature.

Hi,

I agree with @KerstinKeller on the way cmake_paths generator can be very useful, especially for projects with complicated cmake configuration file like ITK or for conan agnostic projects.

Correct me if I am wrong (conan newbie) but with cmake_paths path generator, the path to package roots are added to cmake paths. But, the relevant XXXConfig.cmake path location is in general found in a subfolder (root/lib/cmake/, root/share/cmake). Could conan auto-detect the location of such a CMake configuration file in the package folder and add the right path to the cmake paths?

At the end, I just export a FindXXX.cmake at the root of the package that includes the config file located in a subfolder.

I repeat, as a conan newbie, I might be completely wrong on this one :)

Was this page helpful?
0 / 5 - 0 ratings