CMakeToolchain: Inject arbitrary CMake variables into dependencies
You can find the sources to recreate this project in the examples2 repository in GitHub:
$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/examples/tools/cmake/cmake_toolchain/user_toolchain_profile
In the general case, Conan package recipes provide the necessary abstractions via settings, confs, and options to control different aspects of the build. Many recipes define options
to activate or deactivate features, optional dependencies, or binary characteristics. Configurations like tools.build:cxxflags
can be used to inject arbitrary C++ compile flags.
In some exceptional cases, it might be desired to inject CMake variables directly into dependencies doing CMake builds. This is possible when these dependencies use the CMakeToolchain
integration. Let’s check it in this simple example.
If we have the following package recipe, with a simple conanfile.py
and a CMakeLists.txt
printing a variable:
conanfile.py
from conan import ConanFile
from conan.tools.cmake import CMake
class AppConan(ConanFile):
name = "foo"
version = "1.0"
settings = "os", "compiler", "build_type", "arch"
exports_sources = "CMakeLists.txt"
generators = "CMakeToolchain"
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(foo LANGUAGES NONE)
message(STATUS "MYVAR1 ${MY_USER_VAR1}!!")
We can define a profile file and a myvars.cmake
file (both in the same folder) like the following:
myprofile
include(default)
[conf]
tools.cmake.cmaketoolchain:user_toolchain+={{profile_dir}}/myvars.cmake
Note the {{profile_dir}}
is a jinja template expression that evaluates to the current profile folder, allowing to compute the necessary path to myvars.cmake
file. The tools.cmake.cmaketoolchain:user_toolchain
is a list of files to inject to the generated conan_toolchain.cmake
, so the +=
operator is used to append to it.
The myvars.cmake
can define as many variables as we want:
myvars.cmake
set(MY_USER_VAR1 "MYVALUE1")
Applying this profile, we can see that the package CMake build effectively uses the variable provided in the external myvars.cmake
file:
$ conan create . -pr=myprofile
...
-- MY_USER_VAR1 MYVALUE1
Note that using user_toolchain
while defining values for confs like tools.cmake.cmaketoolchain:system_name
is supported.
Also, user_toolchain
files can define variables for cross-building, such as CMAKE_SYSTEM_NAME
, CMAKE_SYSTEM_VERSION
and CMAKE_SYSTEM_PROCESSOR
. If these variables are defined in the user toolchain file, they will be respected, and the conan_toolchain.cmake
deduced ones will not overwrite the user defined ones. If those variables are not defined in the user toolchain file, then the Conan automatically deduced ones will be used.
The tools.cmake.cmaketoolchain:user_toolchain
conf value might also be passed in the command line -c
argument, but the location of the myvars.cmake
needs to be absolute to be found, as jinja replacement doesn’t happen in the command line.