From f8bd3b41bb5f8bbc83d0b951ed61432c43e4769b Mon Sep 17 00:00:00 2001 From: Carlos Zoido Date: Fri, 14 Nov 2025 14:36:22 +0100 Subject: [PATCH 1/8] add test --- .../toolchains/cmake/test_cmaketoolchain.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/integration/toolchains/cmake/test_cmaketoolchain.py b/test/integration/toolchains/cmake/test_cmaketoolchain.py index ddb732691c0..69b5c534f5c 100644 --- a/test/integration/toolchains/cmake/test_cmaketoolchain.py +++ b/test/integration/toolchains/cmake/test_cmaketoolchain.py @@ -3,6 +3,7 @@ import platform import re import textwrap +from shutil import rmtree import pytest from mock import mock @@ -629,11 +630,22 @@ def generate(self): "CMakeLists.txt": ""}) # File must exist for Conan to do Preset things. client.run("install . -s build_type=Debug") - conan_presets = json.loads(client.load("ConanPresets.json")) assert len(conan_presets["configurePresets"]) == 1 assert conan_presets["configurePresets"][0]["name"] == "conan-release" + # check that if you remove the build folder and regenerate the presets + # the stubs are regenerated correctly + client.run("install . -s build_type=Release") + client.run_command("cmake --list-presets") + assert "'conan-debug' config" in client.out + assert "'conan-release' config" in client.out + + rmtree(os.path.join(client.current_folder, "build")) + client.run("install . -s build_type=Release") + client.run_command("cmake --list-presets") + assert "'conan-release' config" in client.out + def test_cmake_presets_multiconfig(): client = TestClient() From 40d8740c0776c927e0d382910e9b6bf35e91ad75 Mon Sep 17 00:00:00 2001 From: Carlos Zoido Date: Fri, 14 Nov 2025 16:45:19 +0100 Subject: [PATCH 2/8] wip --- conan/tools/cmake/presets.py | 67 ++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/conan/tools/cmake/presets.py b/conan/tools/cmake/presets.py index 8e3dab69b28..9c3d00c725c 100644 --- a/conan/tools/cmake/presets.py +++ b/conan/tools/cmake/presets.py @@ -297,27 +297,41 @@ def generate(conanfile, preset_path, user_presets_path, preset_prefix, preset_da if not os.path.exists(user_presets_path): data = {"version": 4, "vendor": {"conan": dict()}} - for preset, inherits in inherited_user.items(): - for i in inherits: - data.setdefault(preset, []).append({"name": i}) else: data = json.loads(load(user_presets_path)) if "conan" not in data.get("vendor", {}): # The file is not ours, we cannot overwrite it return - if inherited_user: - _IncludingPresets._clean_user_inherits(data, preset_data) + data = _IncludingPresets._append_user_preset_path(data, preset_path, output_dir, absolute_paths) - if not absolute_paths: - try: # Make it relative to the CMakeUserPresets.json if possible - preset_path = os.path.relpath(preset_path, output_dir) - # If we don't normalize, path will be removed in Linux shared folders - # https://github.com/conan-io/conan/issues/18434 - preset_path = preset_path.replace("\\", "/") - except ValueError: - pass - data = _IncludingPresets._append_user_preset_path(data, preset_path, output_dir) + # 1. lee del data el campo include y saca todos los paths absolutos a los presets incluidos si existen + included_files = [] + for inc in data.get("include", []): + inc_path = os.path.join(output_dir, inc) if not absolute_paths else inc + if os.path.exists(inc_path): + included_files.append(inc_path) + + real_preset_names = set() + + for inc_path in included_files: + try: + inc_json = json.loads(load(inc_path)) + except Exception: + continue + for preset_type in ("configurePresets", "buildPresets", "testPresets"): + for p in inc_json.get(preset_type, []): + name = p.get("name") + if name: + real_preset_names.add(name) + + if inherited_user: + for preset_type, inherited_names in inherited_user.items(): + stubs = [ + p for p in inherited_names + if p not in real_preset_names + ] + data[preset_type] = stubs data = json.dumps(data, indent=4) ConanOutput(str(conanfile)).info(f"CMakeToolchain generated: {user_presets_path}") @@ -347,20 +361,29 @@ def _collect_user_inherits(output_dir, preset_prefix): return collected_targets - @staticmethod - def _clean_user_inherits(data, preset_data): - for preset_type in "configurePresets", "buildPresets", "testPresets": - presets = preset_data.get(preset_type, []) - presets_names = [p["name"] for p in presets] - other = data.get(preset_type, []) - other[:] = [p for p in other if p["name"] not in presets_names] + # @staticmethod + # def _clean_user_inherits(data, preset_data): + # for preset_type in "configurePresets", "buildPresets", "testPresets": + # presets = preset_data.get(preset_type, []) + # presets_names = [p["name"] for p in presets] + # other = data.get(preset_type, []) + # other[:] = [p for p in other if p["name"] not in presets_names] @staticmethod - def _append_user_preset_path(data, preset_path, output_dir): + def _append_user_preset_path(data, preset_path, output_dir, absolute_paths): """ - Appends a 'include' to preset_path if the schema supports it. - Otherwise it merges to "data" all the configurePresets, buildPresets etc from the read preset_path. """ + if not absolute_paths: + try: # Make it relative to the CMakeUserPresets.json if possible + preset_path = os.path.relpath(preset_path, output_dir) + # If we don't normalize, path will be removed in Linux shared folders + # https://github.com/conan-io/conan/issues/18434 + preset_path = preset_path.replace("\\", "/") + except ValueError: + pass + if "include" not in data: data["include"] = [] # Clear the folders that have been deleted From 2b0a3de635b8ac0cbb728c06dc38b56da0240c14 Mon Sep 17 00:00:00 2001 From: Carlos Zoido Date: Fri, 14 Nov 2025 17:07:11 +0100 Subject: [PATCH 3/8] wip --- conan/tools/cmake/presets.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/conan/tools/cmake/presets.py b/conan/tools/cmake/presets.py index 9c3d00c725c..484085f0ad9 100644 --- a/conan/tools/cmake/presets.py +++ b/conan/tools/cmake/presets.py @@ -328,7 +328,7 @@ def generate(conanfile, preset_path, user_presets_path, preset_prefix, preset_da if inherited_user: for preset_type, inherited_names in inherited_user.items(): stubs = [ - p for p in inherited_names + {"name": p} for p in inherited_names if p not in real_preset_names ] data[preset_type] = stubs @@ -361,14 +361,6 @@ def _collect_user_inherits(output_dir, preset_prefix): return collected_targets - # @staticmethod - # def _clean_user_inherits(data, preset_data): - # for preset_type in "configurePresets", "buildPresets", "testPresets": - # presets = preset_data.get(preset_type, []) - # presets_names = [p["name"] for p in presets] - # other = data.get(preset_type, []) - # other[:] = [p for p in other if p["name"] not in presets_names] - @staticmethod def _append_user_preset_path(data, preset_path, output_dir, absolute_paths): """ - Appends a 'include' to preset_path if the schema supports it. From d98dd93a500bdcb98c53d6f98768a024abed98f1 Mon Sep 17 00:00:00 2001 From: Carlos Zoido Date: Fri, 14 Nov 2025 17:58:37 +0100 Subject: [PATCH 4/8] wip --- conan/tools/cmake/presets.py | 20 ++++-- .../toolchains/cmake/test_cmaketoolchain.py | 72 +++++++++++++++++++ 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/conan/tools/cmake/presets.py b/conan/tools/cmake/presets.py index 484085f0ad9..5fe90eaf544 100644 --- a/conan/tools/cmake/presets.py +++ b/conan/tools/cmake/presets.py @@ -305,7 +305,7 @@ def generate(conanfile, preset_path, user_presets_path, preset_prefix, preset_da data = _IncludingPresets._append_user_preset_path(data, preset_path, output_dir, absolute_paths) - # 1. lee del data el campo include y saca todos los paths absolutos a los presets incluidos si existen + # Read include field from data and get all absolute paths to included presets if they exist included_files = [] for inc in data.get("include", []): inc_path = os.path.join(output_dir, inc) if not absolute_paths else inc @@ -313,6 +313,7 @@ def generate(conanfile, preset_path, user_presets_path, preset_prefix, preset_da included_files.append(inc_path) real_preset_names = set() + build_preset_to_configure_preset = {} for inc_path in included_files: try: @@ -324,13 +325,22 @@ def generate(conanfile, preset_path, user_presets_path, preset_prefix, preset_da name = p.get("name") if name: real_preset_names.add(name) + if preset_type in ("buildPresets", "testPresets"): + configure_preset = p.get("configurePreset") + if configure_preset: + build_preset_to_configure_preset[name] = configure_preset if inherited_user: for preset_type, inherited_names in inherited_user.items(): - stubs = [ - {"name": p} for p in inherited_names - if p not in real_preset_names - ] + stubs = [] + for p in inherited_names: + if p not in real_preset_names: + stub = {"name": p} + # For buildPresets and testPresets, add configurePreset if mapping exists + # or use the same name if no mapping (assuming same base name) + if preset_type in ("buildPresets", "testPresets"): + stub["configurePreset"] = build_preset_to_configure_preset.get(p, p) + stubs.append(stub) data[preset_type] = stubs data = json.dumps(data, indent=4) diff --git a/test/integration/toolchains/cmake/test_cmaketoolchain.py b/test/integration/toolchains/cmake/test_cmaketoolchain.py index 69b5c534f5c..71b412f826e 100644 --- a/test/integration/toolchains/cmake/test_cmaketoolchain.py +++ b/test/integration/toolchains/cmake/test_cmaketoolchain.py @@ -647,6 +647,78 @@ def generate(self): assert "'conan-release' config" in client.out +@pytest.mark.parametrize("presets", ["CMakePresets.json", "CMakeUserPresets.json"]) +def test_cmake_presets_shared_build_preset(presets): + """valid user preset file is created when multiple project buildPresets inherit + from the same conan buildPresets, and stubs have configurePreset field. + """ + client = TestClient() + project_presets = textwrap.dedent(""" + { + "version": 4, + "cmakeMinimumRequired": { + "major": 3, + "minor": 23, + "patch": 0 + }, + "include":["ConanPresets.json"], + "configurePresets": [ + { + "name": "debug1", + "inherits": ["conan-debug"] + }, + { + "name": "release1", + "inherits": ["conan-release"] + } + ], + "buildPresets": [ + { + "name": "build-debug1", + "configurePreset": "debug1", + "inherits": ["conan-debug"] + }, + { + "name": "build-release1", + "configurePreset": "release1", + "inherits": ["conan-release"] + } + ] + }""") + conanfile = textwrap.dedent(""" + from conan import ConanFile + from conan.tools.cmake import cmake_layout, CMakeToolchain + + class TestPresets(ConanFile): + generators = ["CMakeDeps"] + settings = "build_type" + + def layout(self): + cmake_layout(self) + + def generate(self): + tc = CMakeToolchain(self) + tc.user_presets_path = 'ConanPresets.json' + tc.generate() + """) + + client.save({presets: project_presets, + "conanfile.py": conanfile, + "CMakeLists.txt": ""}) # File must exist for Conan to do Preset things. + + client.run("install . -s build_type=Debug") + conan_presets = json.loads(client.load("ConanPresets.json")) + assert "buildPresets" in conan_presets + build_presets = conan_presets["buildPresets"] + assert len(build_presets) == 1, f"Should have 1 buildPreset stub." + release_stub = build_presets[0] + assert release_stub["name"] == "conan-release" + assert "configurePreset" in release_stub, "buildPreset stub should have configurePreset field" + assert release_stub["configurePreset"] == "conan-release" + client.run_command("cmake --list-presets") + assert "'conan-debug' config" in client.out + + def test_cmake_presets_multiconfig(): client = TestClient() profile = textwrap.dedent(""" From 7fa2954a6eef137e0eb7d15a590017f4269090a3 Mon Sep 17 00:00:00 2001 From: Carlos Zoido Date: Fri, 14 Nov 2025 18:06:36 +0100 Subject: [PATCH 5/8] wip --- conan/tools/cmake/presets.py | 50 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/conan/tools/cmake/presets.py b/conan/tools/cmake/presets.py index 5fe90eaf544..f456c7f6f09 100644 --- a/conan/tools/cmake/presets.py +++ b/conan/tools/cmake/presets.py @@ -305,32 +305,32 @@ def generate(conanfile, preset_path, user_presets_path, preset_prefix, preset_da data = _IncludingPresets._append_user_preset_path(data, preset_path, output_dir, absolute_paths) - # Read include field from data and get all absolute paths to included presets if they exist - included_files = [] - for inc in data.get("include", []): - inc_path = os.path.join(output_dir, inc) if not absolute_paths else inc - if os.path.exists(inc_path): - included_files.append(inc_path) - - real_preset_names = set() - build_preset_to_configure_preset = {} - - for inc_path in included_files: - try: - inc_json = json.loads(load(inc_path)) - except Exception: - continue - for preset_type in ("configurePresets", "buildPresets", "testPresets"): - for p in inc_json.get(preset_type, []): - name = p.get("name") - if name: - real_preset_names.add(name) - if preset_type in ("buildPresets", "testPresets"): - configure_preset = p.get("configurePreset") - if configure_preset: - build_preset_to_configure_preset[name] = configure_preset - if inherited_user: + # Read include field from data and get all absolute paths to included presets if they exist + included_files = [] + for inc in data.get("include", []): + inc_path = os.path.join(output_dir, inc) if not absolute_paths else inc + if os.path.exists(inc_path): + included_files.append(inc_path) + + real_preset_names = set() + build_preset_to_configure_preset = {} + + for inc_path in included_files: + try: + inc_json = json.loads(load(inc_path)) + except Exception: + continue + for preset_type in ("configurePresets", "buildPresets", "testPresets"): + for p in inc_json.get(preset_type, []): + name = p.get("name") + if name: + real_preset_names.add(name) + if preset_type in ("buildPresets", "testPresets"): + configure_preset = p.get("configurePreset") + if configure_preset: + build_preset_to_configure_preset[name] = configure_preset + for preset_type, inherited_names in inherited_user.items(): stubs = [] for p in inherited_names: From 2dab5b51199103136e5032e17b54d94eda923f23 Mon Sep 17 00:00:00 2001 From: Carlos Zoido Date: Mon, 17 Nov 2025 07:32:05 +0100 Subject: [PATCH 6/8] refactor --- conan/tools/cmake/presets.py | 78 +++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/conan/tools/cmake/presets.py b/conan/tools/cmake/presets.py index f456c7f6f09..6328cccd22e 100644 --- a/conan/tools/cmake/presets.py +++ b/conan/tools/cmake/presets.py @@ -306,47 +306,53 @@ def generate(conanfile, preset_path, user_presets_path, preset_prefix, preset_da data = _IncludingPresets._append_user_preset_path(data, preset_path, output_dir, absolute_paths) if inherited_user: - # Read include field from data and get all absolute paths to included presets if they exist - included_files = [] - for inc in data.get("include", []): - inc_path = os.path.join(output_dir, inc) if not absolute_paths else inc - if os.path.exists(inc_path): - included_files.append(inc_path) - - real_preset_names = set() - build_preset_to_configure_preset = {} - - for inc_path in included_files: - try: - inc_json = json.loads(load(inc_path)) - except Exception: - continue - for preset_type in ("configurePresets", "buildPresets", "testPresets"): - for p in inc_json.get(preset_type, []): - name = p.get("name") - if name: - real_preset_names.add(name) - if preset_type in ("buildPresets", "testPresets"): - configure_preset = p.get("configurePreset") - if configure_preset: - build_preset_to_configure_preset[name] = configure_preset - - for preset_type, inherited_names in inherited_user.items(): - stubs = [] - for p in inherited_names: - if p not in real_preset_names: - stub = {"name": p} - # For buildPresets and testPresets, add configurePreset if mapping exists - # or use the same name if no mapping (assuming same base name) - if preset_type in ("buildPresets", "testPresets"): - stub["configurePreset"] = build_preset_to_configure_preset.get(p, p) - stubs.append(stub) - data[preset_type] = stubs + data = _IncludingPresets._update_stubs(data, inherited_user, output_dir, absolute_paths) data = json.dumps(data, indent=4) ConanOutput(str(conanfile)).info(f"CMakeToolchain generated: {user_presets_path}") save(user_presets_path, data) + @staticmethod + def _update_stubs(data, inherited_user, output_dir, absolute_paths): + + included_files = [] + for inc in data.get("include", []): + inc_path = os.path.join(output_dir, inc) if not absolute_paths else inc + if os.path.exists(inc_path): + included_files.append(inc_path) + + # Read include field from data and get all absolute paths to included presets if they exist + real_preset_names = set() + build_preset_to_configure_preset = {} + + for inc_path in included_files: + try: + inc_json = json.loads(load(inc_path)) + except Exception: + continue + for preset_type in ("configurePresets", "buildPresets", "testPresets"): + for p in inc_json.get(preset_type, []): + name = p.get("name") + if name: + real_preset_names.add(name) + if preset_type in ("buildPresets", "testPresets"): + configure_preset = p.get("configurePreset") + if configure_preset: + build_preset_to_configure_preset[name] = configure_preset + + for preset_type, inherited_names in inherited_user.items(): + stubs = [] + for p in inherited_names: + if p not in real_preset_names: + stub = {"name": p} + # For buildPresets and testPresets, add configurePreset if mapping exists + # or use the same name if no mapping (assuming same base name) + if preset_type in ("buildPresets", "testPresets"): + stub["configurePreset"] = build_preset_to_configure_preset.get(p, p) + stubs.append(stub) + data[preset_type] = stubs + return data + @staticmethod def _collect_user_inherits(output_dir, preset_prefix): # Collect all the existing targets in the user files, to create empty conan- presets From c3398a72fe18e2f7762854721b01a1adf01c9260 Mon Sep 17 00:00:00 2001 From: Carlos Zoido Date: Mon, 17 Nov 2025 07:36:33 +0100 Subject: [PATCH 7/8] move tests --- .../cmake/test_cmake_toolchain_presets.py | 147 ++++++++++++++++++ .../toolchains/cmake/test_cmaketoolchain.py | 146 ----------------- 2 files changed, 147 insertions(+), 146 deletions(-) diff --git a/test/functional/toolchains/cmake/test_cmake_toolchain_presets.py b/test/functional/toolchains/cmake/test_cmake_toolchain_presets.py index 0e000172177..26940c2efbb 100644 --- a/test/functional/toolchains/cmake/test_cmake_toolchain_presets.py +++ b/test/functional/toolchains/cmake/test_cmake_toolchain_presets.py @@ -2,6 +2,7 @@ import os import platform import textwrap +from shutil import rmtree import pytest @@ -675,3 +676,149 @@ def generate(self): c.run_command(f"ctest --preset conan-release") assert "tests passed" in c.out + + +@pytest.mark.tool("cmake", "3.23") +@pytest.mark.parametrize("presets", ["CMakePresets.json", "CMakeUserPresets.json"]) +def test_cmake_presets_shared_preset(presets): + """valid user preset file is created when multiple project presets inherit + from the same conan presets. + """ + client = TestClient() + project_presets = textwrap.dedent(""" + { + "version": 4, + "cmakeMinimumRequired": { + "major": 3, + "minor": 23, + "patch": 0 + }, + "include":["ConanPresets.json"], + "configurePresets": [ + { + "name": "debug1", + "inherits": ["conan-debug"] + }, + { + "name": "debug2", + "inherits": ["conan-debug"] + }, + { + "name": "release1", + "inherits": ["conan-release"] + }, + { + "name": "release2", + "inherits": ["conan-release"] + } + ] + }""") + conanfile = textwrap.dedent(""" + from conan import ConanFile + from conan.tools.cmake import cmake_layout, CMakeToolchain + + class TestPresets(ConanFile): + generators = ["CMakeDeps"] + settings = "build_type" + + def layout(self): + cmake_layout(self) + + def generate(self): + tc = CMakeToolchain(self) + tc.user_presets_path = 'ConanPresets.json' + tc.generate() + """) + + client.save({presets: project_presets, + "conanfile.py": conanfile, + "CMakeLists.txt": ""}) # File must exist for Conan to do Preset things. + + client.run("install . -s build_type=Debug") + conan_presets = json.loads(client.load("ConanPresets.json")) + assert len(conan_presets["configurePresets"]) == 1 + assert conan_presets["configurePresets"][0]["name"] == "conan-release" + + # check that if you remove the build folder and regenerate the presets + # the stubs are regenerated correctly + client.run("install . -s build_type=Release") + client.run_command("cmake --list-presets") + assert "'conan-debug' config" in client.out + assert "'conan-release' config" in client.out + + rmtree(os.path.join(client.current_folder, "build")) + client.run("install . -s build_type=Release") + client.run_command("cmake --list-presets") + assert "'conan-release' config" in client.out + + +@pytest.mark.parametrize("presets", ["CMakePresets.json", "CMakeUserPresets.json"]) +def test_cmake_presets_shared_build_preset(presets): + """valid user preset file is created when multiple project buildPresets inherit + from the same conan buildPresets, and stubs have configurePreset field. + """ + client = TestClient() + project_presets = textwrap.dedent(""" + { + "version": 4, + "cmakeMinimumRequired": { + "major": 3, + "minor": 23, + "patch": 0 + }, + "include":["ConanPresets.json"], + "configurePresets": [ + { + "name": "debug1", + "inherits": ["conan-debug"] + }, + { + "name": "release1", + "inherits": ["conan-release"] + } + ], + "buildPresets": [ + { + "name": "build-debug1", + "configurePreset": "debug1", + "inherits": ["conan-debug"] + }, + { + "name": "build-release1", + "configurePreset": "release1", + "inherits": ["conan-release"] + } + ] + }""") + conanfile = textwrap.dedent(""" + from conan import ConanFile + from conan.tools.cmake import cmake_layout, CMakeToolchain + + class TestPresets(ConanFile): + generators = ["CMakeDeps"] + settings = "build_type" + + def layout(self): + cmake_layout(self) + + def generate(self): + tc = CMakeToolchain(self) + tc.user_presets_path = 'ConanPresets.json' + tc.generate() + """) + + client.save({presets: project_presets, + "conanfile.py": conanfile, + "CMakeLists.txt": ""}) # File must exist for Conan to do Preset things. + + client.run("install . -s build_type=Debug") + conan_presets = json.loads(client.load("ConanPresets.json")) + assert "buildPresets" in conan_presets + build_presets = conan_presets["buildPresets"] + assert len(build_presets) == 1, f"Should have 1 buildPreset stub." + release_stub = build_presets[0] + assert release_stub["name"] == "conan-release" + assert "configurePreset" in release_stub, "buildPreset stub should have configurePreset field" + assert release_stub["configurePreset"] == "conan-release" + client.run_command("cmake --list-presets") + assert "'conan-debug' config" in client.out diff --git a/test/integration/toolchains/cmake/test_cmaketoolchain.py b/test/integration/toolchains/cmake/test_cmaketoolchain.py index 71b412f826e..9036d5dbe0b 100644 --- a/test/integration/toolchains/cmake/test_cmaketoolchain.py +++ b/test/integration/toolchains/cmake/test_cmaketoolchain.py @@ -3,7 +3,6 @@ import platform import re import textwrap -from shutil import rmtree import pytest from mock import mock @@ -574,151 +573,6 @@ def layout(self): assert presets["configurePresets"][0]["binaryDir"] == build_dir -@pytest.mark.parametrize("presets", ["CMakePresets.json", "CMakeUserPresets.json"]) -def test_cmake_presets_shared_preset(presets): - """valid user preset file is created when multiple project presets inherit - from the same conan presets. - """ - client = TestClient() - project_presets = textwrap.dedent(""" - { - "version": 4, - "cmakeMinimumRequired": { - "major": 3, - "minor": 23, - "patch": 0 - }, - "include":["ConanPresets.json"], - "configurePresets": [ - { - "name": "debug1", - "inherits": ["conan-debug"] - }, - { - "name": "debug2", - "inherits": ["conan-debug"] - }, - { - "name": "release1", - "inherits": ["conan-release"] - }, - { - "name": "release2", - "inherits": ["conan-release"] - } - ] - }""") - conanfile = textwrap.dedent(""" - from conan import ConanFile - from conan.tools.cmake import cmake_layout, CMakeToolchain - - class TestPresets(ConanFile): - generators = ["CMakeDeps"] - settings = "build_type" - - def layout(self): - cmake_layout(self) - - def generate(self): - tc = CMakeToolchain(self) - tc.user_presets_path = 'ConanPresets.json' - tc.generate() - """) - - client.save({presets: project_presets, - "conanfile.py": conanfile, - "CMakeLists.txt": ""}) # File must exist for Conan to do Preset things. - - client.run("install . -s build_type=Debug") - conan_presets = json.loads(client.load("ConanPresets.json")) - assert len(conan_presets["configurePresets"]) == 1 - assert conan_presets["configurePresets"][0]["name"] == "conan-release" - - # check that if you remove the build folder and regenerate the presets - # the stubs are regenerated correctly - client.run("install . -s build_type=Release") - client.run_command("cmake --list-presets") - assert "'conan-debug' config" in client.out - assert "'conan-release' config" in client.out - - rmtree(os.path.join(client.current_folder, "build")) - client.run("install . -s build_type=Release") - client.run_command("cmake --list-presets") - assert "'conan-release' config" in client.out - - -@pytest.mark.parametrize("presets", ["CMakePresets.json", "CMakeUserPresets.json"]) -def test_cmake_presets_shared_build_preset(presets): - """valid user preset file is created when multiple project buildPresets inherit - from the same conan buildPresets, and stubs have configurePreset field. - """ - client = TestClient() - project_presets = textwrap.dedent(""" - { - "version": 4, - "cmakeMinimumRequired": { - "major": 3, - "minor": 23, - "patch": 0 - }, - "include":["ConanPresets.json"], - "configurePresets": [ - { - "name": "debug1", - "inherits": ["conan-debug"] - }, - { - "name": "release1", - "inherits": ["conan-release"] - } - ], - "buildPresets": [ - { - "name": "build-debug1", - "configurePreset": "debug1", - "inherits": ["conan-debug"] - }, - { - "name": "build-release1", - "configurePreset": "release1", - "inherits": ["conan-release"] - } - ] - }""") - conanfile = textwrap.dedent(""" - from conan import ConanFile - from conan.tools.cmake import cmake_layout, CMakeToolchain - - class TestPresets(ConanFile): - generators = ["CMakeDeps"] - settings = "build_type" - - def layout(self): - cmake_layout(self) - - def generate(self): - tc = CMakeToolchain(self) - tc.user_presets_path = 'ConanPresets.json' - tc.generate() - """) - - client.save({presets: project_presets, - "conanfile.py": conanfile, - "CMakeLists.txt": ""}) # File must exist for Conan to do Preset things. - - client.run("install . -s build_type=Debug") - conan_presets = json.loads(client.load("ConanPresets.json")) - assert "buildPresets" in conan_presets - build_presets = conan_presets["buildPresets"] - assert len(build_presets) == 1, f"Should have 1 buildPreset stub." - release_stub = build_presets[0] - assert release_stub["name"] == "conan-release" - assert "configurePreset" in release_stub, "buildPreset stub should have configurePreset field" - assert release_stub["configurePreset"] == "conan-release" - client.run_command("cmake --list-presets") - assert "'conan-debug' config" in client.out - - def test_cmake_presets_multiconfig(): client = TestClient() profile = textwrap.dedent(""" From fc0060f97bb87c8f2d0d59189ef9b2f3bc091834 Mon Sep 17 00:00:00 2001 From: Carlos Zoido Date: Mon, 17 Nov 2025 11:45:55 +0100 Subject: [PATCH 8/8] use cmake --- test/functional/toolchains/cmake/test_cmake_toolchain_presets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/functional/toolchains/cmake/test_cmake_toolchain_presets.py b/test/functional/toolchains/cmake/test_cmake_toolchain_presets.py index 26940c2efbb..ba021678ee2 100644 --- a/test/functional/toolchains/cmake/test_cmake_toolchain_presets.py +++ b/test/functional/toolchains/cmake/test_cmake_toolchain_presets.py @@ -752,6 +752,7 @@ def generate(self): assert "'conan-release' config" in client.out +@pytest.mark.tool("cmake", "3.23") @pytest.mark.parametrize("presets", ["CMakePresets.json", "CMakeUserPresets.json"]) def test_cmake_presets_shared_build_preset(presets): """valid user preset file is created when multiple project buildPresets inherit