Skip to content

Commit

Permalink
Added support for tools.cmake.cmaketoolchain:extra_variables (#16242)
Browse files Browse the repository at this point in the history
* Added support for tools.cmake.cmaketoolchain:extra_variables (#16222)

* Moved extra_variable from GenericSystemBlock to new block which will be executed later

* Moved extra variables just before the try_compile block.

This will allow users to re-define variables

* Added extra parse layout for cmaketoolchain:extra_variables

Now it admits not only plain key:value pairs but dictionary values in
the form:
{'value': <value>, 'cache': <true/false>, 'type': <cache_type>, 'docstring': <cache docstring> }

* Fix comments
  • Loading branch information
perseoGI authored Jun 3, 2024
1 parent 36148df commit e7b87a3
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 2 deletions.
40 changes: 40 additions & 0 deletions conan/tools/cmake/toolchain/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,46 @@ def context(self):
"winsdk_version": winsdk_version,
"gen_platform_sdk_version": gen_platform_sdk_version}

class ExtraVariablesBlock(Block):
template = textwrap.dedent(r"""
{% if extra_variables %}
{% for key, value in extra_variables.items() %}
set({{ key }} {{ value }})
{% endfor %}
{% endif %}
""")

CMAKE_CACHE_TYPES = ["BOOL","FILEPATH", "PATH", "STRING", "INTERNAL"]

def get_exact_type(self, key, value):
if isinstance(value, str):
return f"\"{value}\""
elif isinstance(value, (int, float)):
return value
elif isinstance(value, dict):
var_value = self.get_exact_type(key, value.get("value"))
is_cache = value.get("cache")
if is_cache:
if not isinstance(is_cache, bool):
raise ConanException(f'tools.cmake.cmaketoolchain:extra_variables "cache" must be a boolean (True/False)')
var_type = value.get("type")
if not var_type:
raise ConanException(f'tools.cmake.cmaketoolchain:extra_variables needs "type" defined for cache variable "{key}"')
if var_type not in self.CMAKE_CACHE_TYPES:
raise ConanException(f'tools.cmake.cmaketoolchain:extra_variables invalid type "{var_type}" for cache variable "{key}". Possible types: {", ".join(self.CMAKE_CACHE_TYPES)}')
# Set docstring as variable name if not defined
docstring = value.get("docstring") or key
return f"{var_value} CACHE {var_type} \"{docstring}\""
else:
return var_value

def context(self):
# Reading configuration from "tools.cmake.cmaketoolchain:extra_variables"
extra_variables = self._conanfile.conf.get("tools.cmake.cmaketoolchain:extra_variables", default={}, check_type=dict)
parsed_extra_variables = {}
for key, value in extra_variables.items():
parsed_extra_variables[key] = self.get_exact_type(key, value)
return {"extra_variables": parsed_extra_variables}

class OutputDirsBlock(Block):

Expand Down
3 changes: 2 additions & 1 deletion conan/tools/cmake/toolchain/toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from conan.tools.build import use_win_mingw
from conan.tools.cmake.presets import write_cmake_presets
from conan.tools.cmake.toolchain import CONAN_TOOLCHAIN_FILENAME
from conan.tools.cmake.toolchain.blocks import ToolchainBlocks, UserToolchain, GenericSystemBlock, \
from conan.tools.cmake.toolchain.blocks import ExtraVariablesBlock, ToolchainBlocks, UserToolchain, GenericSystemBlock, \
AndroidSystemBlock, AppleSystemBlock, FPicBlock, ArchitectureBlock, GLibCXXBlock, VSRuntimeBlock, \
CppStdBlock, ParallelBlock, CMakeFlagsInitBlock, TryCompileBlock, FindFiles, PkgConfigBlock, \
SkipRPath, SharedLibBock, OutputDirsBlock, ExtraFlagsBlock, CompilersBlock, LinkerScriptsBlock, \
Expand Down Expand Up @@ -165,6 +165,7 @@ def __init__(self, conanfile, generator=None):
("parallel", ParallelBlock),
("extra_flags", ExtraFlagsBlock),
("cmake_flags_init", CMakeFlagsInitBlock),
("extra_variables", ExtraVariablesBlock),
("try_compile", TryCompileBlock),
("find_paths", FindFiles),
("pkg_config", PkgConfigBlock),
Expand Down
1 change: 1 addition & 0 deletions conans/model/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"tools.cmake.cmaketoolchain:toolset_arch": "Toolset architecture to be used as part of CMAKE_GENERATOR_TOOLSET in CMakeToolchain",
"tools.cmake.cmaketoolchain:toolset_cuda": "(Experimental) Path to a CUDA toolset to use, or version if installed at the system level",
"tools.cmake.cmaketoolchain:presets_environment": "String to define wether to add or not the environment section to the CMake presets. Empty by default, will generate the environment section in CMakePresets. Can take values: 'disabled'.",
"tools.cmake.cmaketoolchain:extra_variables": "Dictionary with variables to be injected in CMakeToolchain (potential override of CMakeToolchain defined variables)",
"tools.cmake.cmake_layout:build_folder_vars": "Settings and Options that will produce a different build folder and different CMake presets names",
"tools.cmake.cmake_layout:build_folder": "(Experimental) Allow configuring the base folder of the build for local builds",
"tools.cmake.cmake_layout:test_folder": "(Experimental) Allow configuring the base folder of the build for test_package",
Expand Down
57 changes: 56 additions & 1 deletion test/integration/toolchains/cmake/test_cmaketoolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -1501,7 +1501,6 @@ def layout(self):
presets = json.loads(c.load(user_presets["include"][0]))
assert os.path.isabs(presets["configurePresets"][0]["toolchainFile"])


def test_output_dirs_gnudirs_local_default():
# https://github.com/conan-io/conan/issues/14733
c = TestClient()
Expand Down Expand Up @@ -1575,3 +1574,59 @@ def _assert_install(out):
c.run("build .")
_assert_install(c.out)
assert "CMAKE_INSTALL_PREFIX" not in c.out


def test_toolchain_extra_variables():
windows_profile = textwrap.dedent("""
[settings]
os=Windows
arch=x86_64
[conf]
tools.cmake.cmaketoolchain:extra_variables={'CMAKE_GENERATOR_INSTANCE': '${GENERATOR_INSTANCE}/buildTools/', 'FOO': '42' }
""")

client = TestClient()
client.save({"conanfile.txt": "[generators]\nCMakeToolchain",
"windows": windows_profile})

# Test passing extra_variables from pro ile
client.run("install . --profile:host=windows")
toolchain = client.load("conan_toolchain.cmake")
assert 'set(CMAKE_GENERATOR_INSTANCE "${GENERATOR_INSTANCE}/buildTools/")' in toolchain
assert 'set(FOO "42")' in toolchain

# Test input from command line passing dict between doble quotes
client.run(textwrap.dedent(r"""
install . -c tools.cmake.cmaketoolchain:extra_variables="{'CMAKE_GENERATOR_INSTANCE': '${GENERATOR_INSTANCE}/buildTools/', 'FOO': 42.2, 'DICT': {'value': 1}, 'CACHE_VAR': {'value': 'hello world', 'cache': True, 'type': 'BOOL', 'docstring': 'test variable'}}"
""")
)

toolchain = client.load("conan_toolchain.cmake")
assert 'set(CMAKE_GENERATOR_INSTANCE "${GENERATOR_INSTANCE}/buildTools/")' in toolchain
assert 'set(FOO 42.2)' in toolchain
assert 'set(DICT 1)' in toolchain
assert 'set(CACHE_VAR "hello world" CACHE BOOL "test variable")' in toolchain


client.run(textwrap.dedent("""
install . -c tools.cmake.cmaketoolchain:extra_variables="{'invalid': {'value': 'hello world', 'cache': 'true'}}"
""") , assert_error=True)
assert 'tools.cmake.cmaketoolchain:extra_variables "cache" must be a boolean (True/False)' in client.out

# Test invalid cache variable
client.run(textwrap.dedent("""
install . -c tools.cmake.cmaketoolchain:extra_variables="{'invalid': {'value': 'hello world', 'cache': True}}"
""") , assert_error=True)
assert 'tools.cmake.cmaketoolchain:extra_variables needs "type" defined for cache variable "invalid"' in client.out

client.run(textwrap.dedent("""
install . -c tools.cmake.cmaketoolchain:extra_variables="{'invalid': {'value': 'hello world', 'cache': True, 'type': 'INVALID_TYPE'}}"
""") , assert_error=True)
assert 'tools.cmake.cmaketoolchain:extra_variables invalid type "INVALID_TYPE" for cache variable "invalid". Possible types: BOOL, FILEPATH, PATH, STRING, INTERNAL' in client.out

client.run(textwrap.dedent("""
install . -c tools.cmake.cmaketoolchain:extra_variables="{'CACHE_VAR_DEFAULT_DOC': {'value': 'hello world', 'cache': True, 'type': 'PATH'}}"
"""))
toolchain = client.load("conan_toolchain.cmake")
assert 'set(CACHE_VAR_DEFAULT_DOC "hello world" CACHE PATH "CACHE_VAR_DEFAULT_DOC")' in toolchain

0 comments on commit e7b87a3

Please sign in to comment.