Use cmake modules inside a tool_requires
transparently¶
When we want to reuse some .cmake
scripts that are inside another Conan package
there are several possible different scenarios, like if the .cmake
scripts are inside
a regular requires
or a tool_requires
.
Also, it is possible to want 2 different approaches:
- The consumer of the scripts can do a explicit
include(MyScript)
in their CMakeLists.txt. This approach is nicely explicit and simpler to setup, just defineself.cpp_info.builddirs
in the recipe, and consumers withCMakeToolchain
will automatically be able to do theinclude()
and use the functionality. See the example here - The consumer wants to have the dependency cmake modules automatically loaded when the
find_package()
is executed. This current example implements this case.
Let’s say that we have a package, intended to be used as a tool_require
, with the following recipe:
import os
from conan import ConanFile
from conan.tools.files import copy
class Conan(ConanFile):
name = "myfunctions"
version = "1.0"
exports_sources = ["*.cmake"]
def package(self):
copy(self, "*.cmake", self.source_folder, self.package_folder)
def package_info(self):
self.cpp_info.set_property("cmake_build_modules", ["myfunction.cmake"])
And a myfunction.cmake
file in:
function(myfunction)
message("Hello myfunction!!!!")
endfunction()
We can do a cd myfunctions && conan create .
which will create the myfunctions/1.0
package containing the cmake script.
Then, a consumer package will look like:
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain
class Conan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
tool_requires = "myfunctions/1.0"
def generate(self):
tc = CMakeToolchain(self)
tc.generate()
deps = CMakeDeps(self)
# By default 'myfunctions-config.cmake' is not created for tool_requires
# we need to explicitly activate it
deps.build_context_activated = ["myfunctions"]
# and we need to tell to automatically load 'myfunctions' modules
deps.build_context_build_modules = ["myfunctions"]
deps.generate()
def build(self):
cmake = CMake(self)
cmake.configure()
And a CMakeLists.txt
like:
cmake_minimum_required(VERSION 3.0)
project(test)
find_package(myfunctions CONFIG REQUIRED)
myfunction()
Then, the consumer will be able to automatically call the myfunction()
from the dependency module:
$ conan build .
...
Hello myfunction!!!!
If for some reason the consumer wants to force the usage from the tool_requires()
as a CMake module, the consumer could do deps.set_property("myfunctions", "cmake_find_mode", "module", build_context=True)
, and then find_package(myfunctions MODULE REQUIRED)
will work.