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 hereThe 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.